Skip to content

Commit

Permalink
NetP Invite code screen PR 2 (duckduckgo#1883)
Browse files Browse the repository at this point in the history
Task/Issue URL: https://app.asana.com/0/0/1205084446087083/f
BSK PR: duckduckgo/BrowserServicesKit#441

Description:
Second PR for the NetP Invite Code flow. You can find designs in the linked task above. This builds upon duckduckgo#1881 and adds to the existing Invite Code presentation logic in the NetworkProtectionInviteViewModel. It also fleshes out and designs the NetworkProtectionInviteView which has two states:
- codeEntry
- success
This also adds some tests which required some mocks / test helpers for types in the NetworkProtection library in BSK. As we will likely need these on macOS when we come to add more tests there, I added a NetworkProtectionTestUtils library to BSK. This PR points to that BSK branch so I will make sure to point to the BSK release once that’s approved. BSK PR linked above.
  • Loading branch information
graeme authored Aug 3, 2023
1 parent e9a950f commit c1d0cba
Show file tree
Hide file tree
Showing 18 changed files with 547 additions and 98 deletions.
22 changes: 21 additions & 1 deletion DuckDuckGo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -729,15 +729,19 @@
EE0153EB2A6FF970002A8B26 /* NetworkProtectionRootViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE0153EA2A6FF970002A8B26 /* NetworkProtectionRootViewModelTests.swift */; };
EE0153ED2A6FF9E6002A8B26 /* NetworkProtectionRootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE0153EC2A6FF9E6002A8B26 /* NetworkProtectionRootView.swift */; };
EE0153EF2A70021E002A8B26 /* NetworkProtectionInviteView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE0153EE2A70021E002A8B26 /* NetworkProtectionInviteView.swift */; };
EE276BEA2A77F823009167B6 /* NetworkProtectionRootViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE276BE92A77F823009167B6 /* NetworkProtectionRootViewController.swift */; };
EE3B226B29DE0F110082298A /* MockInternalUserStoring.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE3B226A29DE0F110082298A /* MockInternalUserStoring.swift */; };
EE3B226C29DE0FD30082298A /* MockInternalUserStoring.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE3B226A29DE0F110082298A /* MockInternalUserStoring.swift */; };
EE41BD192A729E9C00546C57 /* NetworkProtectionInviteViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE41BD182A729E9C00546C57 /* NetworkProtectionInviteViewModelTests.swift */; };
EE4BE0092A740BED00CD6AA8 /* ClearTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE4BE0082A740BED00CD6AA8 /* ClearTextField.swift */; };
EE4FB1862A28CE7200E5CBA7 /* NetworkProtectionStatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE4FB1852A28CE7200E5CBA7 /* NetworkProtectionStatusView.swift */; };
EE4FB1882A28D11900E5CBA7 /* NetworkProtectionStatusViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE4FB1872A28D11900E5CBA7 /* NetworkProtectionStatusViewModel.swift */; };
EE50052E29C369D300AE0773 /* FeatureFlag.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE50052D29C369D300AE0773 /* FeatureFlag.swift */; };
EE50053029C3BA0800AE0773 /* InternalUserStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE50052F29C3BA0800AE0773 /* InternalUserStore.swift */; };
EE8594992A44791C008A6D06 /* NetworkProtectionTunnelController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE8594982A44791C008A6D06 /* NetworkProtectionTunnelController.swift */; };
EE8E568A2A56BCE400F11DCA /* NetworkProtection in Frameworks */ = {isa = PBXBuildFile; productRef = EE8E56892A56BCE400F11DCA /* NetworkProtection */; };
EEEB80A32A421CE600386378 /* NetworkProtectionPacketTunnelProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEEB80A22A421CE600386378 /* NetworkProtectionPacketTunnelProvider.swift */; };
EEFAB4672A73C230008A38E4 /* NetworkProtectionTestUtils in Frameworks */ = {isa = PBXBuildFile; productRef = EEFAB4662A73C230008A38E4 /* NetworkProtectionTestUtils */; };
EEFD562F2A65B6CA00DAEC48 /* NetworkProtectionInviteViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEFD562E2A65B6CA00DAEC48 /* NetworkProtectionInviteViewModel.swift */; };
EEFE9C732A603CE9005B0A26 /* NetworkProtectionStatusViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEFE9C722A603CE9005B0A26 /* NetworkProtectionStatusViewModelTests.swift */; };
EEFE9C752A603DAD005B0A26 /* MockNetworkProtectionTunnelControlling.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEFE9C742A603DAD005B0A26 /* MockNetworkProtectionTunnelControlling.swift */; };
Expand Down Expand Up @@ -2289,7 +2293,10 @@
EE0153EA2A6FF970002A8B26 /* NetworkProtectionRootViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkProtectionRootViewModelTests.swift; sourceTree = "<group>"; };
EE0153EC2A6FF9E6002A8B26 /* NetworkProtectionRootView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkProtectionRootView.swift; sourceTree = "<group>"; };
EE0153EE2A70021E002A8B26 /* NetworkProtectionInviteView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkProtectionInviteView.swift; sourceTree = "<group>"; };
EE276BE92A77F823009167B6 /* NetworkProtectionRootViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkProtectionRootViewController.swift; sourceTree = "<group>"; };
EE3B226A29DE0F110082298A /* MockInternalUserStoring.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockInternalUserStoring.swift; sourceTree = "<group>"; };
EE41BD182A729E9C00546C57 /* NetworkProtectionInviteViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkProtectionInviteViewModelTests.swift; sourceTree = "<group>"; };
EE4BE0082A740BED00CD6AA8 /* ClearTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClearTextField.swift; sourceTree = "<group>"; };
EE4FB1852A28CE7200E5CBA7 /* NetworkProtectionStatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkProtectionStatusView.swift; sourceTree = "<group>"; };
EE4FB1872A28D11900E5CBA7 /* NetworkProtectionStatusViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkProtectionStatusViewModel.swift; sourceTree = "<group>"; };
EE50052D29C369D300AE0773 /* FeatureFlag.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeatureFlag.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2466,6 +2473,7 @@
files = (
F486D3362506A037002D07D7 /* OHHTTPStubs in Frameworks */,
F486D3382506A225002D07D7 /* OHHTTPStubsSwift in Frameworks */,
EEFAB4672A73C230008A38E4 /* NetworkProtectionTestUtils in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -2860,6 +2868,7 @@
1E24295D293F57FA00584836 /* LottieView.swift */,
1E162604296840D80004127F /* Triangle.swift */,
1E1626062968413B0004127F /* ViewExtension.swift */,
EE4BE0082A740BED00CD6AA8 /* ClearTextField.swift */,
);
name = SwiftUI;
sourceTree = "<group>";
Expand Down Expand Up @@ -4241,6 +4250,7 @@
children = (
EE0153E52A6FE106002A8B26 /* NetworkProtectionRootViewModel.swift */,
EE0153EC2A6FF9E6002A8B26 /* NetworkProtectionRootView.swift */,
EE276BE92A77F823009167B6 /* NetworkProtectionRootViewController.swift */,
);
name = Root;
sourceTree = "<group>";
Expand Down Expand Up @@ -4268,6 +4278,7 @@
EEFE9C722A603CE9005B0A26 /* NetworkProtectionStatusViewModelTests.swift */,
EEFE9C742A603DAD005B0A26 /* MockNetworkProtectionTunnelControlling.swift */,
EE0153EA2A6FF970002A8B26 /* NetworkProtectionRootViewModelTests.swift */,
EE41BD182A729E9C00546C57 /* NetworkProtectionInviteViewModelTests.swift */,
);
name = NetworkProtection;
sourceTree = "<group>";
Expand Down Expand Up @@ -5170,6 +5181,7 @@
packageProductDependencies = (
F486D3352506A037002D07D7 /* OHHTTPStubs */,
F486D3372506A225002D07D7 /* OHHTTPStubsSwift */,
EEFAB4662A73C230008A38E4 /* NetworkProtectionTestUtils */,
);
productName = DuckDuckGoTests;
productReference = 84E341A61E2F7EFB00BDBA6F /* UnitTests.xctest */;
Expand Down Expand Up @@ -5968,6 +5980,7 @@
1E1626072968413B0004127F /* ViewExtension.swift in Sources */,
31A42566285A0A6300049386 /* FaviconViewModel.swift in Sources */,
8C4838B5221C8F7F008A6739 /* GestureToolbarButton.swift in Sources */,
EE276BEA2A77F823009167B6 /* NetworkProtectionRootViewController.swift in Sources */,
986C7FA92417ADE700A3557D /* ReportBrokenSiteViewController.swift in Sources */,
310ECFDD282A8BB0005029B3 /* EnableAutofillSettingsTableViewCell.swift in Sources */,
1E908BF329827C480008C8F3 /* AutoconsentManagement.swift in Sources */,
Expand Down Expand Up @@ -6176,6 +6189,7 @@
310D091D2799F57200DC0060 /* Download.swift in Sources */,
1EEF124E2850EADE003DDE57 /* PrivacyIconView.swift in Sources */,
37FCAAAB29911BF1000E420A /* WaitlistExtensions.swift in Sources */,
EE4BE0092A740BED00CD6AA8 /* ClearTextField.swift in Sources */,
F159BDA41F0BDB5A00B4A01D /* TabViewController.swift in Sources */,
F44D279C27F331BB0037F371 /* AutofillLoginPromptView.swift in Sources */,
CBD4F13E279EBFAB00B20FD7 /* HomeMessageView.swift in Sources */,
Expand Down Expand Up @@ -6356,6 +6370,7 @@
C14882E727F20DAB00D59F0C /* HtmlTestDataLoader.swift in Sources */,
F17D72391E8B35C6003E8B0E /* AppURLsTests.swift in Sources */,
F1134ED61F40F29F00B73467 /* StatisticsUserDefaultsTests.swift in Sources */,
EE41BD192A729E9C00546C57 /* NetworkProtectionInviteViewModelTests.swift in Sources */,
0253A43329E5E393003697C1 /* AppTrackingProtectionAllowlistModelTests.swift in Sources */,
C1B7B53028944E390098FD6A /* RemoteMessagingStoreTests.swift in Sources */,
98EA2C3C218B9AAD0023E1DC /* ThemeManagerTests.swift in Sources */,
Expand Down Expand Up @@ -8341,7 +8356,7 @@
repositoryURL = "https://github.com/DuckDuckGo/BrowserServicesKit";
requirement = {
kind = exactVersion;
version = 71.2.1;
version = 71.3.0;
};
};
C14882EB27F211A000D59F0C /* XCRemoteSwiftPackageReference "SwiftSoup" */ = {
Expand Down Expand Up @@ -8502,6 +8517,11 @@
package = 98A16C2928A11BDE00A6C003 /* XCRemoteSwiftPackageReference "BrowserServicesKit" */;
productName = NetworkProtection;
};
EEFAB4662A73C230008A38E4 /* NetworkProtectionTestUtils */ = {
isa = XCSwiftPackageProductDependency;
package = 98A16C2928A11BDE00A6C003 /* XCRemoteSwiftPackageReference "BrowserServicesKit" */;
productName = NetworkProtectionTestUtils;
};
F42D541C29DCA40B004C4FF1 /* DesignResourcesKit */ = {
isa = XCSwiftPackageProductDependency;
package = F42D541B29DCA40B004C4FF1 /* XCRemoteSwiftPackageReference "DesignResourcesKit" */;
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": "30aeb1c334fcac93366cb9642568c7bcd69cdbef",
"version": "71.2.1"
"revision": "005949a099121192f55b4b5d33ed5d7ce4a12934",
"version": "71.3.0"
}
},
{
Expand Down
12 changes: 12 additions & 0 deletions DuckDuckGo/Assets.xcassets/InviteLock.imageset/Contents.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "Invite-Lock-96.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "Invite-Lock-Success-96.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Binary file not shown.
37 changes: 0 additions & 37 deletions DuckDuckGo/AutofillLoginDetailsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -236,43 +236,6 @@ struct AutofillLoginDetailsView: View {
}
}

struct ClearTextField: View {
var placeholderText: String
@Binding var text: String
var autoCapitalizationType: UITextAutocapitalizationType = .none
var disableAutoCorrection = true
var keyboardType: UIKeyboardType = .default
var secure = false

@State private var closeButtonVisible = false

var body: some View {
HStack {
TextField(placeholderText, text: $text) { editing in
closeButtonVisible = editing
} onCommit: {
closeButtonVisible = false
}
.autocapitalization(autoCapitalizationType)
.disableAutocorrection(disableAutoCorrection)
.keyboardType(keyboardType)
.label4Style(design: secure && text.count > 0 ? .monospaced : .default)

Spacer()
Image("Clear-16")
.opacity(closeButtonOpacity)
.onTapGesture { self.text = "" }
}
}

private var closeButtonOpacity: Double {
if text == "" || !closeButtonVisible {
return 0
}
return 1
}
}

private struct MultilineTextEditor: View {
@Binding var text: String

Expand Down
57 changes: 57 additions & 0 deletions DuckDuckGo/ClearTextField.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
//
// ClearTextField.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.
//

import SwiftUI

struct ClearTextField: View {
var placeholderText: String
@Binding var text: String
var autoCapitalizationType: UITextAutocapitalizationType = .none
var disableAutoCorrection = true
var keyboardType: UIKeyboardType = .default
var secure = false

@State private var closeButtonVisible = false

var body: some View {
HStack {
TextField(placeholderText, text: $text) { editing in
closeButtonVisible = editing
} onCommit: {
closeButtonVisible = false
}
.autocapitalization(autoCapitalizationType)
.disableAutocorrection(disableAutoCorrection)
.keyboardType(keyboardType)
.label4Style(design: secure && text.count > 0 ? .monospaced : .default)

Spacer()
Image("Clear-16")
.opacity(closeButtonOpacity)
.onTapGesture { self.text = "" }
}
}

private var closeButtonOpacity: Double {
if text == "" || !closeButtonVisible {
return 0
}
return 1
}
}
11 changes: 11 additions & 0 deletions DuckDuckGo/NetworkProtectionConvenienceInitialisers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

import NetworkProtection
import UIKit
import Common

extension ConnectionStatusObserverThroughSession {
convenience init() {
Expand All @@ -36,4 +37,14 @@ extension NetworkProtectionKeychainTokenStore {
}
}

extension NetworkProtectionCodeRedemptionCoordinator {
private static var errorEvents: EventMapping<NetworkProtectionError> = .init { _, _, _, _ in
}

// Error events to be added as part of https://app.asana.com/0/1203137811378537/1205112639044115/f
convenience init() {
self.init(tokenStore: NetworkProtectionKeychainTokenStore(), errorEvents: Self.errorEvents)
}
}

#endif
Loading

0 comments on commit c1d0cba

Please sign in to comment.