From d30d28c9dbab88e3797c1994e6c27fb73f2af179 Mon Sep 17 00:00:00 2001 From: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com> Date: Thu, 31 Oct 2024 13:29:43 +0400 Subject: [PATCH] onboarding wip --- apps/ios/Shared/Model/SimpleXAPI.swift | 2 +- .../Onboarding/ChooseServerOperators.swift | 130 ++++++++++++++++++ .../Views/Onboarding/CreateProfile.swift | 4 +- .../Views/Onboarding/OnboardingView.swift | 4 +- apps/ios/SimpleX.xcodeproj/project.pbxproj | 4 + 5 files changed, 140 insertions(+), 4 deletions(-) create mode 100644 apps/ios/Shared/Views/Onboarding/ChooseServerOperators.swift diff --git a/apps/ios/Shared/Model/SimpleXAPI.swift b/apps/ios/Shared/Model/SimpleXAPI.swift index 9297aa7898..a9dbc81842 100644 --- a/apps/ios/Shared/Model/SimpleXAPI.swift +++ b/apps/ios/Shared/Model/SimpleXAPI.swift @@ -1624,7 +1624,7 @@ func startChat(refreshInvitations: Bool = true) throws { withAnimation { let savedOnboardingStage = onboardingStageDefault.get() m.onboardingStage = [.step1_SimpleXInfo, .step2_CreateProfile].contains(savedOnboardingStage) && m.users.count == 1 - ? .step3_CreateSimpleXAddress + ? .step3_ChooseServerOperators : savedOnboardingStage if m.onboardingStage == .onboardingComplete && !privacyDeliveryReceiptsSet.get() { m.setDeliveryReceipts = true diff --git a/apps/ios/Shared/Views/Onboarding/ChooseServerOperators.swift b/apps/ios/Shared/Views/Onboarding/ChooseServerOperators.swift new file mode 100644 index 0000000000..11d2a95d7a --- /dev/null +++ b/apps/ios/Shared/Views/Onboarding/ChooseServerOperators.swift @@ -0,0 +1,130 @@ +// +// ChooseServerOperators.swift +// SimpleX (iOS) +// +// Created by spaced4ndy on 31.10.2024. +// Copyright © 2024 SimpleX Chat. All rights reserved. +// + +import SwiftUI +import SimpleXChat + +struct ChooseServerOperators: View { + @EnvironmentObject var theme: AppTheme + @State private var showInfoSheet = false + @State private var serverOperators: [ServerOperator] = [] + @State private var selectedOperators = Set() + + var body: some View { + GeometryReader { g in + ScrollView { + VStack(alignment: .leading, spacing: 20) { + Text("Choose operators") + .font(.largeTitle) + .bold() + .padding(.top) + + infoText() + + Spacer() + + ForEach(serverOperators) { srvOperator in + operatorCheckView(srvOperator) + .padding(.horizontal) + } + + Spacer() + Spacer() + + continueButton() + .padding(.bottom) + } + .frame(minHeight: g.size.height) + } + } + .frame(maxHeight: .infinity) + .padding() + .onAppear { + serverOperators = ChatModel.shared.serverOperators + selectedOperators = Set(serverOperators.filter { $0.enabled }.map { $0.operatorId }) + } + .sheet(isPresented: $showInfoSheet) { + Text("Info") + } + } + + private func infoText() -> some View { + HStack(spacing: 12) { + Image(systemName: "info.circle") + .resizable() + .scaledToFit() + .frame(width: 20, height: 20) + .foregroundColor(theme.colors.primary) + .onTapGesture { + showInfoSheet = true + } + + Text("Select operators, whose servers you will be using.") + } + } + + @ViewBuilder private func operatorCheckView(_ serverOperator: ServerOperator) -> some View { + let checked = selectedOperators.contains(serverOperator.operatorId) + let icon = checked ? "checkmark.circle.fill" : "circle" + let iconColor = checked ? theme.colors.primary : Color(uiColor: .tertiaryLabel).asAnotherColorFromSecondary(theme) + HStack(spacing: 10) { + Image(serverOperator.info.logo) + .resizable() + .scaledToFit() + .frame(width: 30, height: 30) + Text(serverOperator.name) + .font(.title2) + Spacer() + Image(systemName: icon) + .resizable() + .scaledToFit() + .frame(width: 26, height: 26) + .foregroundColor(iconColor) + } + .background(Color(.systemBackground)) + .onTapGesture { + if checked { + selectedOperators.remove(serverOperator.operatorId) + } else { + selectedOperators.insert(serverOperator.operatorId) + } + } + } + + private func yourServersButton() -> some View { + NavigationLink { + YourServersView() + .navigationTitle("Your servers") + .modifier(ThemedBackground(grouped: true)) + } label: { + Text("Your servers") + } + } + + private func continueButton() -> some View { + HStack { + Spacer() + + Button { + withAnimation { + onboardingStageDefault.set(.step4_SetNotificationsMode) + ChatModel.shared.onboardingStage = .step4_SetNotificationsMode + } + } label: { + Text("Continue") + } + .buttonStyle(.borderedProminent) + + Spacer() + } + } +} + +#Preview { + ChooseServerOperators() +} diff --git a/apps/ios/Shared/Views/Onboarding/CreateProfile.swift b/apps/ios/Shared/Views/Onboarding/CreateProfile.swift index 487f4ccdeb..7892e8b5d4 100644 --- a/apps/ios/Shared/Views/Onboarding/CreateProfile.swift +++ b/apps/ios/Shared/Views/Onboarding/CreateProfile.swift @@ -176,8 +176,8 @@ private func createProfile(_ displayName: String, showAlert: (UserProfileAlert) if m.users.isEmpty || m.users.allSatisfy({ $0.user.hidden }) { try startChat() withAnimation { - onboardingStageDefault.set(.step3_CreateSimpleXAddress) - m.onboardingStage = .step3_CreateSimpleXAddress + onboardingStageDefault.set(.step3_ChooseServerOperators) + m.onboardingStage = .step3_ChooseServerOperators } } else { onboardingStageDefault.set(.onboardingComplete) diff --git a/apps/ios/Shared/Views/Onboarding/OnboardingView.swift b/apps/ios/Shared/Views/Onboarding/OnboardingView.swift index 438491b5f1..77a723ab7c 100644 --- a/apps/ios/Shared/Views/Onboarding/OnboardingView.swift +++ b/apps/ios/Shared/Views/Onboarding/OnboardingView.swift @@ -16,6 +16,7 @@ struct OnboardingView: View { case .step1_SimpleXInfo: SimpleXInfo(onboarding: true) case .step2_CreateProfile: CreateFirstProfile() case .step3_CreateSimpleXAddress: CreateSimpleXAddress() + case .step3_ChooseServerOperators: ChooseServerOperators() case .step4_SetNotificationsMode: SetNotificationsMode() case .onboardingComplete: EmptyView() } @@ -25,7 +26,8 @@ struct OnboardingView: View { enum OnboardingStage: String, Identifiable { case step1_SimpleXInfo case step2_CreateProfile - case step3_CreateSimpleXAddress + case step3_CreateSimpleXAddress // deprecated + case step3_ChooseServerOperators case step4_SetNotificationsMode case onboardingComplete diff --git a/apps/ios/SimpleX.xcodeproj/project.pbxproj b/apps/ios/SimpleX.xcodeproj/project.pbxproj index 7ae601ba9f..af29aab955 100644 --- a/apps/ios/SimpleX.xcodeproj/project.pbxproj +++ b/apps/ios/SimpleX.xcodeproj/project.pbxproj @@ -145,6 +145,7 @@ 640417CD2B29B8C200CCB412 /* NewChatMenuButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 640417CB2B29B8C200CCB412 /* NewChatMenuButton.swift */; }; 640417CE2B29B8C200CCB412 /* NewChatView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 640417CC2B29B8C200CCB412 /* NewChatView.swift */; }; 6407435F2CD2922400158442 /* YourServersView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6407435E2CD2922400158442 /* YourServersView.swift */; }; + 640743612CD360E600158442 /* ChooseServerOperators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 640743602CD360E600158442 /* ChooseServerOperators.swift */; }; 6407BA83295DA85D0082BA18 /* CIInvalidJSONView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6407BA82295DA85D0082BA18 /* CIInvalidJSONView.swift */; }; 6419EC562AB8BC8B004A607A /* ContextInvitingContactMemberView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6419EC552AB8BC8B004A607A /* ContextInvitingContactMemberView.swift */; }; 6419EC582AB97507004A607A /* CIMemberCreatedContactView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6419EC572AB97507004A607A /* CIMemberCreatedContactView.swift */; }; @@ -490,6 +491,7 @@ 640417CB2B29B8C200CCB412 /* NewChatMenuButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NewChatMenuButton.swift; sourceTree = ""; }; 640417CC2B29B8C200CCB412 /* NewChatView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NewChatView.swift; sourceTree = ""; }; 6407435E2CD2922400158442 /* YourServersView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YourServersView.swift; sourceTree = ""; }; + 640743602CD360E600158442 /* ChooseServerOperators.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChooseServerOperators.swift; sourceTree = ""; }; 6407BA82295DA85D0082BA18 /* CIInvalidJSONView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIInvalidJSONView.swift; sourceTree = ""; }; 6419EC552AB8BC8B004A607A /* ContextInvitingContactMemberView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContextInvitingContactMemberView.swift; sourceTree = ""; }; 6419EC572AB97507004A607A /* CIMemberCreatedContactView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIMemberCreatedContactView.swift; sourceTree = ""; }; @@ -886,6 +888,7 @@ 64466DC729FC2B3B00E3D48D /* CreateSimpleXAddress.swift */, 5C9A5BDA2871E05400A5B906 /* SetNotificationsMode.swift */, 5CBD285B29575B8E00EC2CF4 /* WhatsNewView.swift */, + 640743602CD360E600158442 /* ChooseServerOperators.swift */, ); path = Onboarding; sourceTree = ""; @@ -1389,6 +1392,7 @@ 64C06EB52A0A4A7C00792D4D /* ChatItemInfoView.swift in Sources */, 640417CE2B29B8C200CCB412 /* NewChatView.swift in Sources */, 6440CA03288AECA70062C672 /* AddGroupMembersView.swift in Sources */, + 640743612CD360E600158442 /* ChooseServerOperators.swift in Sources */, 5C3F1D58284363C400EC8A82 /* PrivacySettings.swift in Sources */, 5C55A923283CEDE600C4E99E /* SoundPlayer.swift in Sources */, 5C93292F29239A170090FFF9 /* ProtocolServersView.swift in Sources */,