From e609ad33f6d2a88e1d8767a753862acede187c0f Mon Sep 17 00:00:00 2001 From: "tilak.gondi" <115203844+GondiTilak@users.noreply.github.com> Date: Wed, 2 Aug 2023 16:25:14 +0900 Subject: [PATCH] [MINI-5899][iOS Sample] Enable deeplink/QR code to save the Project key and subscription key (#516) * [MINI-5899] [iOS] - Enable deeplinking to Save Project keys using QR Enable passing the Project ID and subscription key using deep link. For eg., miniappdemo://miniapp/settings?projectid=abc&subscription=def **LINK** [MINI-5899](https://jira.rakuten-it.com/jira/browse/MINI-5899) * [MINI-5899] [iOS] - Enable deeplinking to Save Project keys using QR Fix issue of keys not changing when switching List1-List2 in settings screen. **LINK** [MINI-5899](https://jira.rakuten-it.com/jira/browse/MINI-5899) * [MINI-5899] [iOS] - Enable deeplinking to Save Project keys using QR Fix swiftlint violations. **LINK** [MINI-5899](https://jira.rakuten-it.com/jira/browse/MINI-5899) --------- Co-authored-by: leojoseph.r <58416454+rleojoseph@users.noreply.github.com> --- Example/ContentView.swift | 6 ++- .../Settings/MiniAppSettingsView.swift | 54 ++++++++++++------- .../SwiftUI/MiniAppDashboardView.swift | 5 +- Example/Models/SettingsParams.swift | 9 ++++ Example/SampleApp.swift | 52 +++++++++++++++++- Example/SceneDelegate.swift | 32 +++++++++++ Sample.xcodeproj/project.pbxproj | 4 ++ 7 files changed, 139 insertions(+), 23 deletions(-) create mode 100644 Example/Models/SettingsParams.swift diff --git a/Example/ContentView.swift b/Example/ContentView.swift index cfc95efb..4aa33453 100644 --- a/Example/ContentView.swift +++ b/Example/ContentView.swift @@ -1,13 +1,15 @@ import SwiftUI struct ContentView: View { + @StateObject var sharedSettingsVM: MiniAppSettingsViewModel + var body: some View { - MiniAppDashboardView() + MiniAppDashboardView(sharedSettingsVM: sharedSettingsVM) } } struct ContentView_Previews: PreviewProvider { static var previews: some View { - ContentView() + ContentView(sharedSettingsVM: MiniAppSettingsViewModel()) } } diff --git a/Example/Controllers/SwiftUI/Features/Settings/MiniAppSettingsView.swift b/Example/Controllers/SwiftUI/Features/Settings/MiniAppSettingsView.swift index 07a21918..19968313 100644 --- a/Example/Controllers/SwiftUI/Features/Settings/MiniAppSettingsView.swift +++ b/Example/Controllers/SwiftUI/Features/Settings/MiniAppSettingsView.swift @@ -5,8 +5,9 @@ import MiniApp // swiftlint:disable line_length struct MiniAppSettingsView: View { + @Environment(\.presentationMode) var presentationMode - @StateObject var viewModel = MiniAppSettingsViewModel() + @StateObject var viewModel: MiniAppSettingsViewModel @Binding var showFullProgress: Bool @@ -194,20 +195,31 @@ struct MiniAppSettingsView: View { trackButtonTap(pageName: pageName, buttonTitle: "Save") dismissKeyboard() viewModel.save() + viewModel.listConfig.persist() + viewModel.listConfigI.persist() + viewModel.listConfigII.persist() + if presentationMode.wrappedValue.isPresented { + presentationMode.wrappedValue.dismiss() + } } .disabled((viewModel.listConfig.wrappedProjectId.isEmpty || viewModel.listConfig.wrappedSubscriptionKey.isEmpty)) } } + .onAppear { + UITextField.appearance().clearButtonMode = .whileEditing + self.tmpProjectKey = maskedString(of: viewModel.listConfig.projectId ?? "") + self.tmpSubscriptionKey = maskedString(of: viewModel.listConfig.subscriptionKey ?? "") + } .alert(item: $alertMessage) { errorMessage in Alert( title: Text(errorMessage.title), message: Text(errorMessage.message), - dismissButton: .default(Text("Ok")) + dismissButton: .default(Text("Ok"), action: { + self.tmpProjectKey = maskedString(of: viewModel.listConfig.projectId ?? "") + self.tmpSubscriptionKey = maskedString(of: viewModel.listConfig.subscriptionKey ?? "") + }) ) } - .onAppear { - UITextField.appearance().clearButtonMode = .whileEditing - } .onReceive(viewModel.$state) { state in switch state { case .loading: @@ -240,20 +252,13 @@ struct MiniAppSettingsView: View { () } } + .onChange(of: viewModel.listConfig.listType, perform: { _ in + self.dismissKeyboard() + self.updateKeys() + }) .onChange(of: viewModel.listConfig.environmentMode, perform: { _ in self.dismissKeyboard() - switch viewModel.listConfig.environmentMode { - case .production: - viewModel.listConfig.projectId = viewModel.listConfig.projectIdProd - viewModel.listConfig.subscriptionKey = viewModel.listConfig.subscriptionKeyProd - - case .staging: - viewModel.listConfig.projectId = viewModel.listConfig.projectIdStaging - viewModel.listConfig.subscriptionKey = viewModel.listConfig.subscriptionKeyStaging - - } - self.tmpProjectKey = maskedString(of: viewModel.listConfig.projectId ?? "") - self.tmpSubscriptionKey = maskedString(of: viewModel.listConfig.subscriptionKey ?? "") + self.updateKeys() }) .trackPage(pageName: pageName) } @@ -262,6 +267,19 @@ struct MiniAppSettingsView: View { UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil) } + func updateKeys() { + switch viewModel.listConfig.environmentMode { + case .production: + viewModel.listConfig.projectId = viewModel.listConfig.projectIdProd + viewModel.listConfig.subscriptionKey = viewModel.listConfig.subscriptionKeyProd + case .staging: + viewModel.listConfig.projectId = viewModel.listConfig.projectIdStaging + viewModel.listConfig.subscriptionKey = viewModel.listConfig.subscriptionKeyStaging + } + self.tmpProjectKey = maskedString(of: viewModel.listConfig.projectId ?? "") + self.tmpSubscriptionKey = maskedString(of: viewModel.listConfig.subscriptionKey ?? "") + } + var hasListIErrors: Bool { return viewModel.listConfigI.error != nil } @@ -300,7 +318,7 @@ extension MiniAppSettingsView: ViewTrackable { struct MiniAppFeatureConfigView_Previews: PreviewProvider { static var previews: some View { - MiniAppSettingsView(showFullProgress: .constant(false)) + MiniAppSettingsView(viewModel: MiniAppSettingsViewModel(), showFullProgress: .constant(false)) } } // swiftlint:enable line_length diff --git a/Example/Controllers/SwiftUI/MiniAppDashboardView.swift b/Example/Controllers/SwiftUI/MiniAppDashboardView.swift index 017b1ef2..768a2468 100644 --- a/Example/Controllers/SwiftUI/MiniAppDashboardView.swift +++ b/Example/Controllers/SwiftUI/MiniAppDashboardView.swift @@ -9,6 +9,7 @@ class MiniAppDashboardViewModel: ObservableObject { struct MiniAppDashboardView: View { @StateObject var viewModel = MiniAppDashboardViewModel() + @StateObject var sharedSettingsVM: MiniAppSettingsViewModel @State var sampleMiniAppId: String = "" @State var sampleMiniAppVersion: String = "" @@ -51,7 +52,7 @@ struct MiniAppDashboardView: View { .tag(2) NavigationView { - MiniAppSettingsView(showFullProgress: $isPresentingFullProgress) + MiniAppSettingsView(viewModel: sharedSettingsVM, showFullProgress: $isPresentingFullProgress) } .navigationViewStyle(.stack) .tabItem { @@ -95,6 +96,6 @@ struct MiniAppDashboardView: View { struct MiniAppDashboardView_Previews: PreviewProvider { static var previews: some View { - MiniAppDashboardView() + MiniAppDashboardView(sharedSettingsVM: MiniAppSettingsViewModel()) } } diff --git a/Example/Models/SettingsParams.swift b/Example/Models/SettingsParams.swift new file mode 100644 index 00000000..ddbb0be0 --- /dev/null +++ b/Example/Models/SettingsParams.swift @@ -0,0 +1,9 @@ +import Foundation + +struct SettingsParams: Equatable { + var tab: Int = 1 + var projectId: String = "" + var subscriptionKey: String = "" + var isProduction: Bool = false + var isPreviewMode: Bool = false +} diff --git a/Example/SampleApp.swift b/Example/SampleApp.swift index 52a65a7b..6249b9b2 100644 --- a/Example/SampleApp.swift +++ b/Example/SampleApp.swift @@ -9,11 +9,12 @@ struct SampleApp: App { let store = MiniAppStore.shared let deepLinkManager = DeeplinkManager() + @StateObject var sharedSettingsViewModel = MiniAppSettingsViewModel() @State var deepLink: SampleAppDeeplink? var body: some Scene { WindowGroup { - ContentView() + ContentView(sharedSettingsVM: sharedSettingsViewModel) .accentColor(.red) .onOpenURL { url in let receivedDeepLink = deepLinkManager.manage(url: url) @@ -40,6 +41,9 @@ struct SampleApp: App { print(error) } } + case let .settings(settinsInfo): + prepareSettingsViewModel(with: settinsInfo) + deepLink = .settings(viewModel: self.sharedSettingsViewModel) } } .sheet(item: $deepLink) { @@ -56,19 +60,65 @@ struct SampleApp: App { ) } .accentColor(.red) + case .settings(let viewModel): + NavigationView { + MiniAppSettingsView(viewModel: viewModel, showFullProgress: .constant(false)) + } + .accentColor(.red) } } } } + + func prepareSettingsViewModel(with params: SettingsParams) { + if params.tab == 1 { + let list1 = self.setConfigValues(with: params, for: ListConfiguration(listType: .listI)) + sharedSettingsViewModel.listConfig = list1 + sharedSettingsViewModel.listConfigI = list1 + sharedSettingsViewModel.listConfigI.persist() + } else { + let list2 = self.setConfigValues(with: params, for: ListConfiguration(listType: .listII)) + sharedSettingsViewModel.listConfig = list2 + sharedSettingsViewModel.listConfigII = list2 + sharedSettingsViewModel.listConfigII.persist() + } + sharedSettingsViewModel.listConfig.persist() + sharedSettingsViewModel.selectedListConfig = params.tab == 1 ? .listI : .listII + } + + func setConfigValues(with params: SettingsParams, for listConfig: ListConfiguration) -> ListConfiguration { + var listConfig = listConfig + if params.isProduction { + listConfig.environmentMode = .production + listConfig.projectIdProd = params.projectId + listConfig.subscriptionKey = params.subscriptionKey + } else { + listConfig.environmentMode = .staging + listConfig.projectIdStaging = params.projectId + listConfig.subscriptionKeyStaging = params.subscriptionKey + } + if params.isPreviewMode { + listConfig.previewMode = .previewable + } else { + listConfig.previewMode = .published + } + listConfig.projectId = params.projectId + listConfig.subscriptionKey = params.subscriptionKey + listConfig.persist() + return listConfig + } } enum SampleAppDeeplink: Identifiable { case miniapp(info: MiniAppInfo) + case settings(viewModel: MiniAppSettingsViewModel) var id: String { switch self { case .miniapp(let info): return info.id + "_" + info.version.versionId + case .settings(let queryParams): + return "SettingsConfig" } } } diff --git a/Example/SceneDelegate.swift b/Example/SceneDelegate.swift index 21e7324e..b60b3932 100644 --- a/Example/SceneDelegate.swift +++ b/Example/SceneDelegate.swift @@ -44,12 +44,14 @@ class DeeplinkManager { enum Path: String { case qrcode = "preview" case deeplink = "dl" + case settings = "settings" } enum Target: Equatable, Identifiable { case unknown case qrcode(code: String) case deeplink(id: String) + case settings(settingsParams: SettingsParams) var id: String { switch self { @@ -59,6 +61,8 @@ class DeeplinkManager { return code case let .deeplink(id): return id + case let .settings(settingsParams): + return settingsParams.projectId } } } @@ -77,6 +81,34 @@ class DeeplinkManager { case .deeplink: guard url.pathComponents.count > 1 else { return .unknown } return .deeplink(id: url.pathComponents[2]) + case .settings: + guard url.pathComponents.count > 1 else { return .unknown } + let settingsParams = self.getQueryItems(url.absoluteString) + return .settings(settingsParams: settingsParams) + } + } + + func getQueryItems(_ urlString: String) -> SettingsParams { + var queryItems: [String: String] = [:] + let components: NSURLComponents? = getURLComonents(urlString) + for item in components?.queryItems ?? [] { + queryItems[item.name] = item.value?.removingPercentEncoding + } + var settingsParams = SettingsParams() + settingsParams.tab = Int(queryItems["tab"] ?? "") ?? 1 + settingsParams.projectId = queryItems["projectid"] ?? "" + settingsParams.subscriptionKey = queryItems["subscription"] ?? "" + settingsParams.isProduction = Bool(queryItems["isProduction"] ?? "") ?? false + settingsParams.isPreviewMode = Bool(queryItems["isPreviewMode"] ?? "") ?? false + return settingsParams + } + + func getURLComonents(_ urlString: String?) -> NSURLComponents? { + var components: NSURLComponents? + let linkUrl = URL(string: urlString?.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed) ?? "") + if let linkUrl = linkUrl { + components = NSURLComponents(url: linkUrl, resolvingAgainstBaseURL: true) } + return components } } diff --git a/Sample.xcodeproj/project.pbxproj b/Sample.xcodeproj/project.pbxproj index bf1b10f6..cd21cab3 100644 --- a/Sample.xcodeproj/project.pbxproj +++ b/Sample.xcodeproj/project.pbxproj @@ -17,6 +17,7 @@ 1C0A785C29C3417500433A38 /* AppTrackingTransparency.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1C0A785A29C3417500433A38 /* AppTrackingTransparency.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; 1C0C5C892A0C973300CB1F63 /* HostAppThemeColorsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C0C5C882A0C973300CB1F63 /* HostAppThemeColorsView.swift */; }; 1C2E06AE293A6A99003C6380 /* MiniAppSecureStorageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C2E06AD293A6A99003C6380 /* MiniAppSecureStorageView.swift */; }; + 1C3FCFEB2A666DB3003C7A05 /* SettingsParams.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C3FCFEA2A666DB3003C7A05 /* SettingsParams.swift */; }; 1C6BAB472A5519340012E800 /* MAAnalyticsInfoLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C6BAB462A5519340012E800 /* MAAnalyticsInfoLogger.swift */; }; 1C6BAB4B2A5522F60012E800 /* MAAnalyticsInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C6BAB4A2A5522F60012E800 /* MAAnalyticsInfoView.swift */; }; 1CD1591829421FDF001E0E21 /* UniversalBridgeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CD1591729421FDF001E0E21 /* UniversalBridgeView.swift */; }; @@ -156,6 +157,7 @@ 1C0A785A29C3417500433A38 /* AppTrackingTransparency.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppTrackingTransparency.framework; path = System/Library/Frameworks/AppTrackingTransparency.framework; sourceTree = SDKROOT; }; 1C0C5C882A0C973300CB1F63 /* HostAppThemeColorsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HostAppThemeColorsView.swift; sourceTree = ""; }; 1C2E06AD293A6A99003C6380 /* MiniAppSecureStorageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MiniAppSecureStorageView.swift; sourceTree = ""; }; + 1C3FCFEA2A666DB3003C7A05 /* SettingsParams.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsParams.swift; sourceTree = ""; }; 1C6BAB462A5519340012E800 /* MAAnalyticsInfoLogger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MAAnalyticsInfoLogger.swift; sourceTree = ""; }; 1C6BAB4A2A5522F60012E800 /* MAAnalyticsInfoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MAAnalyticsInfoView.swift; sourceTree = ""; }; 1CD1591729421FDF001E0E21 /* UniversalBridgeView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UniversalBridgeView.swift; sourceTree = ""; }; @@ -447,6 +449,7 @@ children = ( 38920AD5251D9C57004C5DDD /* UserProfileModel.swift */, A13C249726A15048003ADC6D /* UserPointsModel.swift */, + 1C3FCFEA2A666DB3003C7A05 /* SettingsParams.swift */, ); path = Models; sourceTree = ""; @@ -880,6 +883,7 @@ F70DD8EC28D417C4003EF1F1 /* MiniAppSettingsQAView.swift in Sources */, F70DD8EA28D417C4003EF1F1 /* MiniAppSettingsProfileView.swift in Sources */, F70DD8E828D417C4003EF1F1 /* MiniAppSettingsView+Config.swift in Sources */, + 1C3FCFEB2A666DB3003C7A05 /* SettingsParams.swift in Sources */, F70DD8F628D417C4003EF1F1 /* MiniAppWithTermsView.swift in Sources */, A13198012918A45C00B839E8 /* View+Events.swift in Sources */, F70DD8EE28D417C4003EF1F1 /* MiniAppSettingsAccessTokenView.swift in Sources */,