mirror of https://github.com/oxen-io/session-ios
				
				
				
			
			You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			261 lines
		
	
	
		
			9.0 KiB
		
	
	
	
		
			Swift
		
	
			
		
		
	
	
			261 lines
		
	
	
		
			9.0 KiB
		
	
	
	
		
			Swift
		
	
| // Copyright © 2023 Rangeproof Pty Ltd. All rights reserved.
 | |
| 
 | |
| import SwiftUI
 | |
| import Combine
 | |
| import SessionUIKit
 | |
| import SessionSnodeKit
 | |
| import SignalUtilitiesKit
 | |
| import SessionUtilitiesKit
 | |
| 
 | |
| enum PNMode {
 | |
|     case fast
 | |
|     case slow
 | |
| }
 | |
| 
 | |
| struct PNModeScreen: View {
 | |
|     @EnvironmentObject var host: HostWrapper
 | |
|     
 | |
|     @State private var currentSelection: PNMode = .fast
 | |
|     
 | |
|     private let dependencies: Dependencies
 | |
|     
 | |
|     public init(using dependencies: Dependencies) {
 | |
|         self.dependencies = dependencies
 | |
|     }
 | |
|     
 | |
|     let options: [PNOptionView.Info] = [
 | |
|         PNOptionView.Info(
 | |
|             mode: .fast,
 | |
|             title: "notificationsFastMode".localized(),
 | |
|             explanation: "notificationsFastModeDescriptionIos".localized(),
 | |
|             isRecommended: true,
 | |
|             accessibility: Accessibility(
 | |
|                 identifier: "Fast mode notifications button",
 | |
|                 label: "Fast mode notifications button"
 | |
|             )
 | |
|         ),
 | |
|         PNOptionView.Info(
 | |
|             mode: .slow,
 | |
|             title: "notificationsSlowMode".localized(),
 | |
|             explanation: "notificationsSlowModeDescription"
 | |
|                 .put(key: "app_name", value: Constants.app_name)
 | |
|                 .localized(),
 | |
|             isRecommended: false,
 | |
|             accessibility: Accessibility(
 | |
|                 identifier: "Slow mode notifications button",
 | |
|                 label: "Slow mode notifications button"
 | |
|             )
 | |
|         )
 | |
|     ]
 | |
|     
 | |
|     var body: some View {
 | |
|         ZStack(alignment: .center) {
 | |
|             ThemeManager.currentTheme.colorSwiftUI(for: .backgroundPrimary).ignoresSafeArea()
 | |
|             
 | |
|             VStack(
 | |
|                 alignment: .leading,
 | |
|                 spacing: Values.mediumSpacing
 | |
|             ) {
 | |
|                 Spacer()
 | |
|                 
 | |
|                 Text("notificationsMessage".localized())
 | |
|                     .bold()
 | |
|                     .font(.system(size: Values.veryLargeFontSize))
 | |
|                     .foregroundColor(themeColor: .textPrimary)
 | |
|                 
 | |
|                 Text(
 | |
|                     "onboardingMessageNotificationExplanation"
 | |
|                         .put(key: "app_name", value: Constants.app_name)
 | |
|                         .localized()
 | |
|                 )
 | |
|                 .font(.system(size: Values.smallFontSize))
 | |
|                 .foregroundColor(themeColor: .textPrimary)
 | |
|                 .padding(.vertical, Values.mediumSpacing)
 | |
|                 
 | |
|                 VStack(
 | |
|                     alignment: .leading,
 | |
|                     spacing: Values.mediumSpacing)
 | |
|                 {
 | |
|                     ForEach(
 | |
|                         0...(options.count - 1),
 | |
|                         id: \.self
 | |
|                     ) { index in
 | |
|                         PNOptionView(
 | |
|                             currentSelection: $currentSelection,
 | |
|                             info: options[index]
 | |
|                         )
 | |
|                         .accessibility(options[index].accessibility)
 | |
|                     }
 | |
|                 }
 | |
|                 
 | |
|                 Spacer()
 | |
|             }
 | |
|             .padding(.horizontal, Values.veryLargeSpacing)
 | |
|             .padding(.bottom, Values.massiveSpacing + Values.largeButtonHeight)
 | |
|             
 | |
|             VStack() {
 | |
|                 Spacer()
 | |
|                 
 | |
|                 Button {
 | |
|                     register()
 | |
|                 } label: {
 | |
|                     Text("theContinue".localized())
 | |
|                         .bold()
 | |
|                         .font(.system(size: Values.smallFontSize))
 | |
|                         .foregroundColor(themeColor: .sessionButton_text)
 | |
|                         .frame(
 | |
|                             maxWidth: .infinity,
 | |
|                             maxHeight: Values.largeButtonHeight,
 | |
|                             alignment: .center
 | |
|                         )
 | |
|                         .overlay(
 | |
|                             Capsule()
 | |
|                                 .stroke(themeColor: .sessionButton_border)
 | |
|                         )
 | |
|                 }
 | |
|                 .accessibility(
 | |
|                     Accessibility(
 | |
|                         identifier: "Continue",
 | |
|                         label: "Continue"
 | |
|                     )
 | |
|                 )
 | |
|                 .padding(.horizontal, Values.massiveSpacing)
 | |
|             }
 | |
|             .padding(.vertical, Values.mediumSpacing)
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     private func register() {
 | |
|         // Store whether we want to use APNS
 | |
|         dependencies.mutate(cache: .onboarding) { $0.setUserAPNS(currentSelection == .fast) }
 | |
|         
 | |
|         // If we are registering then we can just continue on
 | |
|         guard dependencies[cache: .onboarding].initialFlow != .register else {
 | |
|             return completeRegistration()
 | |
|         }
 | |
|         
 | |
|         // Check if we already have a profile name (ie. profile retrieval completed while waiting on
 | |
|         // this screen)
 | |
|         guard dependencies[cache: .onboarding].displayName.isEmpty else {
 | |
|             // If we have one then we can go straight to the home screen
 | |
|             return self.completeRegistration()
 | |
|         }
 | |
|         
 | |
|         // If we don't have one then show a loading indicator and try to retrieve the existing name
 | |
|         let viewController: SessionHostingViewController = SessionHostingViewController(
 | |
|             rootView: LoadingScreen(using: dependencies)
 | |
|         )
 | |
|         viewController.setUpNavBarSessionIcon(using: dependencies)
 | |
|         self.host.controller?.navigationController?.pushViewController(viewController, animated: true)
 | |
|     }
 | |
|     
 | |
|     private func completeRegistration() {
 | |
|         dependencies.mutate(cache: .onboarding) { [dependencies] onboarding in
 | |
|             let shouldSyncPushTokens: Bool = onboarding.useAPNS
 | |
|             
 | |
|             onboarding.completeRegistration {
 | |
|                 // Trigger the 'SyncPushTokensJob' directly as we don't want to wait for paths to build
 | |
|                 // before requesting the permission from the user
 | |
|                 if shouldSyncPushTokens { SyncPushTokensJob.run(uploadOnlyIfStale: false, using: dependencies) }
 | |
|                 
 | |
|                 let homeVC: HomeVC = HomeVC(using: dependencies)
 | |
|                 dependencies[singleton: .app].setHomeViewController(homeVC)
 | |
|                 self.host.controller?.navigationController?.setViewControllers([ homeVC ], animated: true)
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| struct PNOptionView: View {
 | |
|     
 | |
|     struct Info {
 | |
|         let mode: PNMode
 | |
|         let title: String
 | |
|         let explanation: String
 | |
|         let isRecommended: Bool
 | |
|         let accessibility: Accessibility
 | |
|     }
 | |
|     
 | |
|     @Binding var currentSelection: PNMode
 | |
|     
 | |
|     let info: Info
 | |
|     
 | |
|     static let cornerRadius: CGFloat = 8
 | |
|     static let radioBorderSize: CGFloat = 22
 | |
|     static let radioSelectionSize: CGFloat = 17
 | |
|     
 | |
|     var body: some View {
 | |
|         HStack(
 | |
|             spacing: Values.largeSpacing
 | |
|         ) {
 | |
|             VStack(
 | |
|                 alignment: .leading,
 | |
|                 spacing: Values.smallSpacing
 | |
|             ) {
 | |
|                 Text(info.title)
 | |
|                     .bold()
 | |
|                     .font(.system(size: Values.mediumFontSize))
 | |
|                     .foregroundColor(themeColor: .textPrimary)
 | |
|                 
 | |
|                 Text(info.explanation)
 | |
|                     .font(.system(size: Values.verySmallFontSize))
 | |
|                     .foregroundColor(themeColor: .textPrimary)
 | |
|                     .frame(
 | |
|                         maxWidth: .infinity,
 | |
|                         alignment: .leading
 | |
|                     )
 | |
|                 
 | |
|                 if info.isRecommended {
 | |
|                     Text("recommended".localized())
 | |
|                         .bold()
 | |
|                         .font(.system(size: Values.smallFontSize))
 | |
|                         .foregroundColor(themeColor: .primary)
 | |
|                 }
 | |
|             }
 | |
|             .frame(maxWidth: .infinity)
 | |
|             .padding(.all, Values.mediumSpacing)
 | |
|             .overlay(
 | |
|                 RoundedRectangle(
 | |
|                     cornerSize: CGSize(
 | |
|                         width: Self.cornerRadius,
 | |
|                         height: Self.cornerRadius
 | |
|                     )
 | |
|                 )
 | |
|                 .stroke(themeColor: .borderSeparator)
 | |
|             )
 | |
|             
 | |
|             ZStack(alignment: .center) {
 | |
|                 Circle()
 | |
|                     .stroke(themeColor: .textPrimary)
 | |
|                     .frame(
 | |
|                         width: Self.radioBorderSize,
 | |
|                         height: Self.radioBorderSize
 | |
|                     )
 | |
|                 
 | |
|                 if currentSelection == info.mode {
 | |
|                     Circle()
 | |
|                         .fill(themeColor: .primary)
 | |
|                         .frame(
 | |
|                             width: Self.radioSelectionSize,
 | |
|                             height: Self.radioSelectionSize
 | |
|                         )
 | |
|                 }
 | |
|             }
 | |
|             .accessibility(info.accessibility)
 | |
|         }
 | |
|         .frame(
 | |
|             maxWidth: .infinity
 | |
|         )
 | |
|         .contentShape(Rectangle())
 | |
|         .onTapGesture {
 | |
|             currentSelection = info.mode
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| struct PNModeView_Previews: PreviewProvider {
 | |
|     static var previews: some View {
 | |
|         PNModeScreen(using: Dependencies.createEmpty())
 | |
|     }
 | |
| }
 |