Files
simplex-chat/apps/ios/Shared/Views/Onboarding/YourNetwork.swift
T
Evgeny 3d85480944 ui: new onboarding (#6888)
* ui: onboarding assets

* android: fix gradle version check, pass assets dir to builds

* desktop: pass assets dir to gradle builds

* ui: new onboarding (#6872)

* ios: improve onboarding

* ios version condition

* android strings

* merge keys

* refactor network conditions to old location

* ios scroll headline

* remove nav view

* kotlin: refactor network commitments page to use existing view

* remove unused keys

* update why page

* configure -> setup

* padding for app bar in why page

* fix why page

* padding

* copy translations from the website

* export localizations

* export again

* kotlin: fix why page

* fix

* import localizations

* custom layout

* padding for system bars

* paddings

* more paddings

* more padding 2

* update fonts

* fonts

* line height, padding

* paddings

* refactor notifications

* refactor ios

* notification icons in cards

* restore profile field

* padding

* desktop layout create profile

* fix

* more layout

* create profile layout

* mobile padding

* split mobile and desktop

* layout

* layout

* background

* refactor onboarding images

* use DARK theme by default

* page 3 and 4 layouts

* restructure desktop onboarding to two panes

* improve layout

* improve

* fonts, padding

* link mobile on full page

* fix, reduce noise

* change to animation

* fix animation

* refactor

* colors, animation

* import

* details

* fix padding

* fix icon

* fix

* button paddings

* accept button on terms page

* fix conditions button

* close modal

---------

Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
Co-authored-by: shum <github.shum@liber.li>
Co-authored-by: Evgeny @ SimpleX Chat <259188159+evgeny-simplex@users.noreply.github.com>
2026-04-27 11:46:08 +01:00

194 lines
6.7 KiB
Swift

//
// YourNetwork.swift
// SimpleX (iOS)
//
// Created by Evgeny on 22/04/2026.
// Copyright © 2026 SimpleX Chat. All rights reserved.
//
import SwiftUI
import SimpleXChat
private enum YourNetworkSheet: Identifiable {
case configureOperators
case configureNotifications
var id: String {
switch self {
case .configureOperators: return "configureOperators"
case .configureNotifications: return "configureNotifications"
}
}
}
struct YourNetworkView: View {
@EnvironmentObject var theme: AppTheme
@Environment(\.colorScheme) var colorScheme: ColorScheme
@State private var serverOperators: [ServerOperator] = []
@State private var selectedOperatorIds = Set<Int64>()
@State private var notificationMode: NotificationsMode = .instant
@State private var sheetItem: YourNetworkSheet? = nil
@State private var nextStepNavLinkActive = false
@State private var justOpened = true
var body: some View {
GeometryReader { g in
VStack(alignment: .center, spacing: 10) {
Spacer(minLength: 0)
#if SIMPLEX_ASSETS
Image(colorScheme == .light ? "your-network" : "your-network-light")
.resizable()
.scaledToFit()
.frame(maxWidth: .infinity)
#else
ZStack {
let gp = OnboardingCardView.gradientPoints(aspectRatio: 1.0, scale: colorScheme == .light ? 1.2 : 1.5)
LinearGradient(
stops: colorScheme == .light ? OnboardingCardView.lightStops : OnboardingCardView.darkStops,
startPoint: gp.start,
endPoint: gp.end
)
Image(systemName: "network")
.font(.system(size: 72))
.foregroundColor(theme.colors.primary)
}
.aspectRatio(1.0, contentMode: .fit)
.clipShape(RoundedRectangle(cornerRadius: 24))
.padding(.horizontal, 25)
.frame(maxWidth: .infinity)
#endif
Text("Your network")
.font(.largeTitle)
.bold()
.multilineTextAlignment(.center)
.fixedSize(horizontal: false, vertical: true)
.padding(.top, 15)
Text("Network routers cannot know\nwho talks to whom")
.font(.title3)
.fontWeight(.medium)
.foregroundColor(theme.colors.secondary)
.multilineTextAlignment(.center)
.fixedSize(horizontal: false, vertical: true)
VStack(alignment: .leading, spacing: 20) {
configureRoutersButton()
configureNotificationsButton()
}
.padding(.top, 15)
.padding(.bottom, 15)
Spacer(minLength: 0)
continueButton()
.padding(.bottom, g.safeAreaInsets.bottom == 0 ? 20 : 0)
}
.padding(.horizontal, 25)
.padding(.top, 8)
.padding(.bottom, 20)
.frame(minHeight: g.size.height)
}
.onAppear {
if justOpened {
serverOperators = ChatModel.shared.conditions.serverOperators
selectedOperatorIds = Set(serverOperators.filter { $0.enabled }.map { $0.operatorId })
justOpened = false
}
}
.sheet(item: $sheetItem) { item in
switch item {
case .configureOperators:
ChooseServerOperators(serverOperators: serverOperators, selectedOperatorIds: $selectedOperatorIds)
.modifier(ThemedBackground())
case .configureNotifications:
SetNotificationsMode(notificationMode: $notificationMode)
.modifier(ThemedBackground())
}
}
.frame(maxHeight: .infinity)
.navigationBarHidden(true)
}
private func configureRoutersButton() -> some View {
Button {
sheetItem = .configureOperators
} label: {
HStack(spacing: 6) {
Text("Setup routers")
.fontWeight(.medium)
ForEach(serverOperators.reversed()) { op in
Image(op.logo(colorScheme))
.resizable()
.scaledToFit()
.frame(width: 22, height: 22)
.grayscale(selectedOperatorIds.contains(op.operatorId) ? 0.0 : 1.0)
}
}
}
}
private func configureNotificationsButton() -> some View {
Button {
sheetItem = .configureNotifications
} label: {
HStack(spacing: 4) {
Text("Setup notifications")
.fontWeight(.medium)
Image(systemName: notificationMode.icon)
}
}
}
private func continueButton() -> some View {
ZStack {
Button {
applyNotificationMode()
onboardingStageDefault.set(.step4_NetworkCommitments)
nextStepNavLinkActive = true
} label: {
Text("Continue")
}
.buttonStyle(OnboardingButtonStyle())
NavigationLink(isActive: $nextStepNavLinkActive) {
OnboardingConditionsView(selectedOperatorIds: selectedOperatorIds)
.navigationBarBackButtonHidden(true)
.modifier(ThemedBackground())
} label: {
EmptyView()
}
.frame(width: 1, height: 1)
.hidden()
}
}
private func applyNotificationMode() {
let m = ChatModel.shared
if let token = m.deviceToken {
switch notificationMode {
case .off:
m.tokenStatus = .new
m.notificationMode = .off
default:
Task {
do {
let status = try await apiRegisterToken(token: token, notificationMode: notificationMode)
await MainActor.run {
m.tokenStatus = status
m.notificationMode = notificationMode
}
} catch let error {
let a = getErrorAlert(error, "Error enabling notifications")
AlertManager.shared.showAlertMsg(
title: a.title,
message: a.message
)
}
}
}
}
}
}