Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add toggling of NetP Notifications to iOS #2112

Merged
merged 25 commits into from
Oct 31, 2023
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
21a255b
Add NotificationsView with just the settings link
graeme Oct 19, 2023
44212a0
Add notifications authorization flow
graeme Oct 20, 2023
1ed5878
Fix init typo
graeme Oct 20, 2023
b8565bf
Point to dev BSK commit
graeme Oct 20, 2023
1454f88
Fix header
graeme Oct 20, 2023
e6653dd
Add NetP User defaults
graeme Oct 20, 2023
0967bd2
NetP US project changes
graeme Oct 20, 2023
57f896e
Inject notificationsPresenter w/ NetP defaults
graeme Oct 20, 2023
778204e
Add authorized view with notifications toggling
graeme Oct 20, 2023
062ddc6
Add animation
graeme Oct 20, 2023
6280ca1
Fix issue with delegation
graeme Oct 20, 2023
026091d
Fix threading issues
graeme Oct 20, 2023
e91dc80
Add an explanatory comment
graeme Oct 20, 2023
22372eb
Fix issue where reload reverts to empty
graeme Oct 20, 2023
5e6f49f
Add the netP group ID to main entitlements
graeme Oct 20, 2023
b25ec34
Fix animation bug on status view
graeme Oct 20, 2023
f6a7386
Add footer text for turning on notifications
graeme Oct 20, 2023
e26bb98
Point to latest BSK version
graeme Oct 20, 2023
d6f20cf
Merge branch 'develop' into graeme/ios-vpn-notification-settings
graeme Oct 20, 2023
e2d08fc
Move view model init into convenience init
graeme Oct 20, 2023
691a990
Wrap the whole PTP in a NetP check to fix release
graeme Oct 20, 2023
f8e0161
Update DuckDuckGo/NetworkProtectionVPNNotificationsView.swift
graeme Oct 31, 2023
303ccdd
Point to 82.1.0
graeme Oct 31, 2023
b146678
Package.resolved
graeme Oct 31, 2023
b3c8fb6
Merge remote-tracking branch 'origin/develop' into graeme/ios-vpn-not…
graeme Oct 31, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions Core/UserDefaults+NetworkProtection.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//
// UserDefaults+NetworkProtection.swift
// DuckDuckGo
//
// Copyright © 2023 DuckDuckGo. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

#if NETWORK_PROTECTION

import Foundation

public extension UserDefaults {
static var networkProtectionGroupDefaults: UserDefaults {
let suiteName = "\(Global.groupIdPrefix).netp"
guard let defaults = UserDefaults(suiteName: suiteName) else {
fatalError("Failed to create netP UserDefaults")
}
return defaults
}
Comment on lines +25 to +31
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, I suspect I'll be using this for the widget - thanks!

}

#endif
32 changes: 30 additions & 2 deletions DuckDuckGo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -765,6 +765,11 @@
EE8594992A44791C008A6D06 /* NetworkProtectionTunnelController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE8594982A44791C008A6D06 /* NetworkProtectionTunnelController.swift */; };
EE8E568A2A56BCE400F11DCA /* NetworkProtection in Frameworks */ = {isa = PBXBuildFile; productRef = EE8E56892A56BCE400F11DCA /* NetworkProtection */; };
EE9D68D12AE00CF300B55EF4 /* NetworkProtectionVPNSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE9D68D02AE00CF300B55EF4 /* NetworkProtectionVPNSettingsView.swift */; };
EE9D68D52AE1526600B55EF4 /* NetworkProtectionVPNNotificationsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE9D68D42AE1526600B55EF4 /* NetworkProtectionVPNNotificationsView.swift */; };
EE9D68D82AE15AD600B55EF4 /* UIApplicationExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE9D68D72AE15AD600B55EF4 /* UIApplicationExtension.swift */; };
EE9D68DA2AE1659F00B55EF4 /* NetworkProtectionVPNNotificationsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE9D68D92AE1659F00B55EF4 /* NetworkProtectionVPNNotificationsViewModel.swift */; };
EE9D68DC2AE16AE100B55EF4 /* NotificationsAuthorizationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE9D68DB2AE16AE100B55EF4 /* NotificationsAuthorizationController.swift */; };
EE9D68DE2AE2A65600B55EF4 /* UserDefaults+NetworkProtection.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE9D68DD2AE2A65600B55EF4 /* UserDefaults+NetworkProtection.swift */; };
EEDFE2DA2AC6ED4F00F0E19C /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = EEDFE2DC2AC6ED4F00F0E19C /* Localizable.strings */; };
EEEB80A32A421CE600386378 /* NetworkProtectionPacketTunnelProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEEB80A22A421CE600386378 /* NetworkProtectionPacketTunnelProvider.swift */; };
EEF0F8CC2ABC832300630031 /* NetworkProtectionDebugFeatures.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEF0F8CB2ABC832200630031 /* NetworkProtectionDebugFeatures.swift */; };
Expand Down Expand Up @@ -2334,6 +2339,11 @@
EE7A92862AC6DE4700832A36 /* NetworkProtectionNotificationIdentifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkProtectionNotificationIdentifier.swift; sourceTree = "<group>"; };
EE8594982A44791C008A6D06 /* NetworkProtectionTunnelController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkProtectionTunnelController.swift; sourceTree = "<group>"; };
EE9D68D02AE00CF300B55EF4 /* NetworkProtectionVPNSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkProtectionVPNSettingsView.swift; sourceTree = "<group>"; };
EE9D68D42AE1526600B55EF4 /* NetworkProtectionVPNNotificationsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkProtectionVPNNotificationsView.swift; sourceTree = "<group>"; };
EE9D68D72AE15AD600B55EF4 /* UIApplicationExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIApplicationExtension.swift; sourceTree = "<group>"; };
EE9D68D92AE1659F00B55EF4 /* NetworkProtectionVPNNotificationsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkProtectionVPNNotificationsViewModel.swift; sourceTree = "<group>"; };
EE9D68DB2AE16AE100B55EF4 /* NotificationsAuthorizationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationsAuthorizationController.swift; sourceTree = "<group>"; };
EE9D68DD2AE2A65600B55EF4 /* UserDefaults+NetworkProtection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UserDefaults+NetworkProtection.swift"; sourceTree = "<group>"; };
EEB8FDB92A990AEE00EBEDCF /* Configuration-Alpha.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Configuration-Alpha.xcconfig"; path = "Configuration/Configuration-Alpha.xcconfig"; sourceTree = "<group>"; };
EEDFE2DB2AC6ED4F00F0E19C /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
EEDFE2DD2AC6ED5B00F0E19C /* bg */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = bg; path = bg.lproj/Localizable.strings; sourceTree = "<group>"; };
Expand Down Expand Up @@ -4348,6 +4358,7 @@
children = (
EE0153E02A6EABE0002A8B26 /* NetworkProtectionConvenienceInitialisers.swift */,
EE458D0C2AB1DA4600FC651A /* EventMapping+NetworkProtectionError.swift */,
EE9D68DB2AE16AE100B55EF4 /* NotificationsAuthorizationController.swift */,
);
name = Helpers;
sourceTree = "<group>";
Expand Down Expand Up @@ -4411,6 +4422,7 @@
isa = PBXGroup;
children = (
EE7A92862AC6DE4700832A36 /* NetworkProtectionNotificationIdentifier.swift */,
EE9D68DD2AE2A65600B55EF4 /* UserDefaults+NetworkProtection.swift */,
);
name = NetworkProtection;
sourceTree = "<group>";
Expand All @@ -4423,9 +4435,19 @@
name = VPNSettings;
sourceTree = "<group>";
};
EE9D68D62AE1527F00B55EF4 /* VPNNotifications */ = {
isa = PBXGroup;
children = (
EE9D68D42AE1526600B55EF4 /* NetworkProtectionVPNNotificationsView.swift */,
EE9D68D92AE1659F00B55EF4 /* NetworkProtectionVPNNotificationsViewModel.swift */,
);
name = VPNNotifications;
sourceTree = "<group>";
};
EECD94B22A28B8580085C66E /* NetworkProtection */ = {
isa = PBXGroup;
children = (
EE9D68D62AE1527F00B55EF4 /* VPNNotifications */,
EE9D68CF2AE00CE000B55EF4 /* VPNSettings */,
EE458D122ABB651500FC651A /* Debug */,
EE0153E22A6FE031002A8B26 /* Root */,
Expand Down Expand Up @@ -5108,6 +5130,7 @@
F1DE78591E5CD2A70058895A /* UIViewExtension.swift */,
F1F5337B1F26A9EF00D80D4F /* UserText.swift */,
986DA94924884B18004A7E39 /* WebViewTransition.swift */,
EE9D68D72AE15AD600B55EF4 /* UIApplicationExtension.swift */,
);
name = UserInterface;
sourceTree = "<group>";
Expand Down Expand Up @@ -6114,6 +6137,7 @@
F1DE78581E5CAE350058895A /* TabViewGridCell.swift in Sources */,
984D035824ACCC6F0066CFB8 /* TabViewListCell.swift in Sources */,
B6BA95C328891E33004ABA20 /* BrowsingMenuAnimator.swift in Sources */,
EE9D68DC2AE16AE100B55EF4 /* NotificationsAuthorizationController.swift in Sources */,
AA3D854923DA1DFB00788410 /* AppIcon.swift in Sources */,
8590CB612684D0600089F6BF /* CookieDebugViewController.swift in Sources */,
319A37152829A55F0079FBCE /* AutofillListItemTableViewCell.swift in Sources */,
Expand All @@ -6135,6 +6159,7 @@
1E8AD1C727BE9B2900ABA377 /* DownloadsListDataSource.swift in Sources */,
3157B43527F497F50042D3D7 /* SaveLoginViewController.swift in Sources */,
853C5F6121C277C7001F7A05 /* global.swift in Sources */,
EE9D68D82AE15AD600B55EF4 /* UIApplicationExtension.swift in Sources */,
F13B4BD31F1822C700814661 /* Tab.swift in Sources */,
F1BE54581E69DE1000FCF649 /* TutorialSettings.swift in Sources */,
1EE52ABB28FB1D6300B750C1 /* UIImageExtension.swift in Sources */,
Expand All @@ -6156,6 +6181,7 @@
C1B7B529289420830098FD6A /* RemoteMessaging.xcdatamodeld in Sources */,
986B16C425E92DF0007D23E8 /* BrowsingMenuViewController.swift in Sources */,
988AC355257E47C100793C64 /* RequeryLogic.swift in Sources */,
EE9D68D52AE1526600B55EF4 /* NetworkProtectionVPNNotificationsView.swift in Sources */,
1E4F4A5A297193DE00625985 /* MainViewController+CookiesManaged.swift in Sources */,
8586A10D24CBA7070049720E /* FindInPageActivity.swift in Sources */,
1E1626072968413B0004127F /* ViewExtension.swift in Sources */,
Expand Down Expand Up @@ -6440,6 +6466,7 @@
8586A11024CCCD040049720E /* TabsBarViewController.swift in Sources */,
F1D796F41E7C2A410019D451 /* BookmarksDelegate.swift in Sources */,
C1B7B52428941F2A0098FD6A /* RemoteMessageRequest.swift in Sources */,
EE9D68DA2AE1659F00B55EF4 /* NetworkProtectionVPNNotificationsViewModel.swift in Sources */,
1E8AD1D727C2E24E00ABA377 /* DownloadsListRowViewModel.swift in Sources */,
C1B0F6422AB08BE9001EAF05 /* MockPrivacyConfiguration.swift in Sources */,
1E865AF0272042DB001C74F3 /* TextSizeSettingsViewController.swift in Sources */,
Expand Down Expand Up @@ -6699,6 +6726,7 @@
CB2A7EF4285383B300885F67 /* AppLastCompiledRulesStore.swift in Sources */,
4B75EA9226A266CB00018634 /* PrintingUserScript.swift in Sources */,
37445F972A155F7C0029F789 /* SyncDataProviders.swift in Sources */,
EE9D68DE2AE2A65600B55EF4 /* UserDefaults+NetworkProtection.swift in Sources */,
CB258D1F29A52B2500DEBA24 /* Configuration.swift in Sources */,
9847C00027A2DDBB00DB07AA /* AppPrivacyConfigurationDataProvider.swift in Sources */,
F143C3281E4A9A0E00CFDE3A /* StringExtension.swift in Sources */,
Expand Down Expand Up @@ -8977,8 +9005,8 @@
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/DuckDuckGo/BrowserServicesKit";
requirement = {
kind = exactVersion;
version = 81.4.1;
kind = revision;
revision = f2a5d102da34842b3ef02c876a1a539648bd5930;
};
};
C14882EB27F211A000D59F0C /* XCRemoteSwiftPackageReference "SwiftSoup" */ = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
"repositoryURL": "https://github.com/DuckDuckGo/BrowserServicesKit",
"state": {
"branch": null,
"revision": "57d8ed94cf503fdbd348420e821df00142660333",
"version": "81.4.1"
"revision": "f2a5d102da34842b3ef02c876a1a539648bd5930",
"version": null
}
},
{
Expand Down
1 change: 1 addition & 0 deletions DuckDuckGo/DuckDuckGo.entitlements
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
<string>$(GROUP_ID_PREFIX).statistics</string>
<string>$(GROUP_ID_PREFIX).database</string>
<string>$(GROUP_ID_PREFIX).apptp</string>
<string>$(GROUP_ID_PREFIX).netp</string>
</array>
</dict>
</plist>
10 changes: 10 additions & 0 deletions DuckDuckGo/NetworkProtectionConvenienceInitialisers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,14 @@ extension NetworkProtectionCodeRedemptionCoordinator {
}
}

extension NetworkProtectionVPNNotificationsViewModel {
convenience init() {
let notificationsSettingsStore = NetworkProtectionNotificationsSettingsUserDefaultsStore(userDefaults: .networkProtectionGroupDefaults)
self.init(
notificationsAuthorization: NotificationsAuthorizationController(),
notificationsSettingsStore: notificationsSettingsStore
)
}
}

#endif
9 changes: 6 additions & 3 deletions DuckDuckGo/NetworkProtectionStatusView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,12 @@ struct NetworkProtectionStatusView: View {
}
settings()
}
.animation(.default, value: statusModel.shouldShowError)
.padding(.top, statusModel.error == nil ? 0 : -20)
.animation(.default, value: statusModel.shouldShowConnectionDetails)
.if(statusModel.animationsOn, transform: {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The animation bug this fixes became a lot more noticeable with the addition of the new section. So I fixed it here.

$0
.animation(.default, value: statusModel.shouldShowConnectionDetails)
.animation(.default, value: statusModel.shouldShowError)
})
.applyInsetGroupedListStyle()
.navigationTitle(UserText.netPNavTitle)
}
Expand Down Expand Up @@ -134,7 +137,7 @@ struct NetworkProtectionStatusView: View {
NavigationLink(UserText.netPVPNSettingsTitle, destination: NetworkProtectionVPNSettingsView())
.font(.system(size: 16))
.foregroundColor(.textPrimary)
NavigationLink(UserText.netPVPNNotificationsTitle, destination: Text("Coming soon!"))
NavigationLink(UserText.netPVPNNotificationsTitle, destination: NetworkProtectionVPNNotificationsView())
.font(.system(size: 16))
.foregroundColor(.textPrimary)
} header: {
Expand Down
6 changes: 6 additions & 0 deletions DuckDuckGo/NetworkProtectionStatusViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ final class NetworkProtectionStatusViewModel: ObservableObject {
@Published public var location: String?
@Published public var ipAddress: String?

@Published public var animationsOn: Bool = false

public init(tunnelController: TunnelController = NetworkProtectionTunnelController(),
statusObserver: ConnectionStatusObserver = ConnectionStatusObserverThroughSession(),
serverInfoObserver: ConnectionServerInfoObserver = ConnectionServerInfoObserverThroughSession(),
Expand Down Expand Up @@ -166,7 +168,11 @@ final class NetworkProtectionStatusViewModel: ObservableObject {
.store(in: &cancellables)
}

@MainActor
func didToggleNetP(to enabled: Bool) async {
// This is to prevent weird looking animations on navigating to the screen.
// It makes sense as animations should mostly only happen when a user has interacted.
animationsOn = true
if enabled {
await enableNetP()
} else {
Expand Down
90 changes: 90 additions & 0 deletions DuckDuckGo/NetworkProtectionVPNNotificationsView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
//
// NetworkProtectionVPNNotificationsView.swift
// DuckDuckGo
//
// Copyright © 2023 DuckDuckGo. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

#if NETWORK_PROTECTION

import SwiftUI
import UIKit
import NetworkProtection
import Core

@available(iOS 15, *)
struct NetworkProtectionVPNNotificationsView: View {
@StateObject var model = NetworkProtectionVPNNotificationsViewModel()

var body: some View {
List {
switch model.viewKind {
case .loading:
EmptyView()
case .unauthorized:
unauthorizedView
case .authorized:
authorizedView
}
}
.animation(.default, value: model.viewKind)
.applyInsetGroupedListStyle()
.navigationTitle(UserText.netPVPNNotificationsTitle).onAppear {
Task {
await model.onViewAppeared()
}
}
}

@ViewBuilder
private var unauthorizedView: some View {
Section {
Button(UserText.netPTurnOnNotificationsButtonTitle) {
model.turnOnNotifications()
}
.foregroundColor(.controlColor)
} footer: {
Text(UserText.netPTurnOnNotificationsSectionFooter)
.foregroundColor(.textSecondary)
.font(.system(size: 13))
.padding(.top, 6)
}
}

@ViewBuilder
private var authorizedView: some View {
Section {
Toggle(UserText.netPVPNAlertsToggleTitle, isOn: Binding(
get: { model.alertsEnabled },
set: model.didToggleAlerts(to:)
))
.toggleStyle(SwitchToggleStyle(tint: Color(designSystemColor: .accent)))
graeme marked this conversation as resolved.
Show resolved Hide resolved
} footer: {
Text(UserText.netPVPNAlertsToggleSectionFooter)
.foregroundColor(.textSecondary)
.font(.system(size: 13))
.padding(.top, 6)
}
}
}

private extension Color {
static let textPrimary = Color(designSystemColor: .textPrimary)
static let textSecondary = Color(designSystemColor: .textSecondary)
static let cellBackground = Color(designSystemColor: .surface)
static let controlColor = Color(designSystemColor: .accent)
}

#endif
Loading