diff --git a/DuckDuckGo/SyncSettingsViewController.swift b/DuckDuckGo/SyncSettingsViewController.swift index 50ddc47dec..059b28fd26 100644 --- a/DuckDuckGo/SyncSettingsViewController.swift +++ b/DuckDuckGo/SyncSettingsViewController.swift @@ -56,7 +56,13 @@ class SyncSettingsViewController: UIHostingController { self.syncService = syncService self.syncBookmarksAdapter = syncBookmarksAdapter - let viewModel = SyncSettingsViewModel() + let viewModel = SyncSettingsViewModel( + isOnDevEnvironment: { syncService.serverEnvironment == .development }, + switchToProdEnvironment: { + syncService.updateServerEnvironment(.production) + UserDefaults.standard.set(ServerEnvironment.production.description, forKey: UserDefaultsWrapper.Key.syncEnvironment.rawValue) + } + ) super.init(rootView: SyncSettingsView(model: viewModel)) diff --git a/DuckDuckGoTests/SyncManagementViewModelTests.swift b/DuckDuckGoTests/SyncManagementViewModelTests.swift index 5edc9b8ba4..3fbf7ba3fa 100644 --- a/DuckDuckGoTests/SyncManagementViewModelTests.swift +++ b/DuckDuckGoTests/SyncManagementViewModelTests.swift @@ -26,7 +26,7 @@ class SyncManagementViewModelTests: XCTestCase, SyncManagementViewModelDelegate fileprivate var monitor = Monitor() lazy var model: SyncSettingsViewModel = { - let model = SyncSettingsViewModel() + let model = SyncSettingsViewModel(isOnDevEnvironment: { false }, switchToProdEnvironment: {}) model.delegate = self return model }() diff --git a/LocalPackages/SyncUI/Sources/SyncUI/ViewModels/SyncSettingsViewModel.swift b/LocalPackages/SyncUI/Sources/SyncUI/ViewModels/SyncSettingsViewModel.swift index 6923a9322d..c4d11a852f 100644 --- a/LocalPackages/SyncUI/Sources/SyncUI/ViewModels/SyncSettingsViewModel.swift +++ b/LocalPackages/SyncUI/Sources/SyncUI/ViewModels/SyncSettingsViewModel.swift @@ -85,8 +85,16 @@ public class SyncSettingsViewModel: ObservableObject { @Published var recoveryCode = "" public weak var delegate: SyncManagementViewModelDelegate? - - public init() { } + private(set) var isOnDevEnvironment: Bool + private(set) var switchToProdEnvironment: () -> Void = {} + + public init(isOnDevEnvironment: @escaping () -> Bool, switchToProdEnvironment: @escaping () -> Void) { + self.isOnDevEnvironment = isOnDevEnvironment() + self.switchToProdEnvironment = { [weak self] in + switchToProdEnvironment() + self?.isOnDevEnvironment = isOnDevEnvironment() + } + } func disableSync() { isBusy = true diff --git a/LocalPackages/SyncUI/Sources/SyncUI/Views/SyncSettingsView.swift b/LocalPackages/SyncUI/Sources/SyncUI/Views/SyncSettingsView.swift index b6c38f5de1..02e6e171e7 100644 --- a/LocalPackages/SyncUI/Sources/SyncUI/Views/SyncSettingsView.swift +++ b/LocalPackages/SyncUI/Sources/SyncUI/Views/SyncSettingsView.swift @@ -27,6 +27,7 @@ public struct SyncSettingsView: View { let timer = Timer.publish(every: 3, on: .main, in: .common).autoconnect() @State var isSyncWithSetUpSheetVisible = false @State var isRecoverSyncedDataSheetVisible = false + @State var isEnvironmentSwitcherInstructionsVisible = false public init(model: SyncSettingsViewModel) { self.model = model @@ -121,6 +122,8 @@ extension SyncSettingsView { } Spacer() } + } header: { + devEnvironmentIndicator() } footer: { HStack { Spacer() @@ -265,6 +268,7 @@ extension SyncSettingsView { .fill(.green) .frame(width: 8) .padding(.bottom, 1) + devEnvironmentIndicator() } } footer: { Text(UserText.turnSyncOffSectionFooter) @@ -344,6 +348,36 @@ extension SyncSettingsView { } } + @ViewBuilder + func devEnvironmentIndicator() -> some View { + if model.isOnDevEnvironment { + Button(action: { + isEnvironmentSwitcherInstructionsVisible.toggle() + }, label: { + if #available(iOS 15.0, *) { + Text("Dev environment") + .daxFootnoteRegular() + .padding(.horizontal, 10) + .padding(.vertical, 2) + .foregroundColor(.white) + .background(Color.red40) + .clipShape(RoundedRectangle(cornerRadius: 10)) + } else { + Text("Dev environment") + } + }) + .alert(isPresented: $isEnvironmentSwitcherInstructionsVisible) { + Alert( + title: Text("You're using Sync Development environment"), + primaryButton: .default(Text("Keep Development")), + secondaryButton: .destructive(Text("Switch to Production"), action: model.switchToProdEnvironment) + ) + } + } else { + EmptyView() + } + } + enum LimitedItemType { case bookmarks case credentials