import SwiftUI struct OnboardingView: View { @State private var screen: Screen = .welcome @EnvironmentObject private var identityManager: IdentityManager enum Screen { case welcome case createNew case restore } var body: some View { NavigationStack { switch screen { case .welcome: WelcomeView(onCreate: { screen = .createNew }, onRestore: { screen = .restore }) case .createNew: CreateMnemonicView(onBack: { screen = .welcome }) case .restore: RestoreMnemonicView(onBack: { screen = .welcome }) } } } } private struct WelcomeView: View { let onCreate: () -> Void let onRestore: () -> Void var body: some View { VStack(spacing: 32) { Spacer() Image(systemName: "infinity.circle.fill") .font(.system(size: 80)) .foregroundStyle(.tint) Text("Montana") .font(.system(size: 48, weight: .bold)) Text("Цифровая собственность.\nПостквантовая криптография.\nТвой ключ — твоя идентичность.") .font(.body) .multilineTextAlignment(.center) .foregroundStyle(.secondary) .padding(.horizontal) Spacer() VStack(spacing: 12) { Button(action: onCreate) { Text("Создать новую идентичность") .frame(maxWidth: .infinity) } .buttonStyle(.borderedProminent) .controlSize(.large) Button(action: onRestore) { Text("Восстановить из мнемоники") .frame(maxWidth: .infinity) } .buttonStyle(.bordered) .controlSize(.large) } .padding(.horizontal) Spacer().frame(height: 24) } } } private struct CreateMnemonicView: View { let onBack: () -> Void @EnvironmentObject private var identityManager: IdentityManager @State private var mnemonic: String = "" @State private var confirmedSaved = false @State private var error: String? var body: some View { ScrollView { VStack(alignment: .leading, spacing: 16) { Text("Запишите 24 слова в надёжное место") .font(.title2.bold()) Text("Это единственный способ восстановить идентичность. Никому не показывайте.") .font(.footnote) .foregroundStyle(.secondary) if !mnemonic.isEmpty { MnemonicGridView(mnemonic: mnemonic) } if let error { Text(error) .foregroundStyle(.red) .font(.footnote) } Toggle("Я записал(-а) все 24 слова", isOn: $confirmedSaved) .padding(.top) Button { do { try identityManager.restore(from: mnemonic) } catch { self.error = String(describing: error) } } label: { Text("Завершить настройку") .frame(maxWidth: .infinity) } .buttonStyle(.borderedProminent) .controlSize(.large) .disabled(!confirmedSaved || mnemonic.isEmpty) } .padding() } .navigationTitle("Новая идентичность") .toolbar { ToolbarItem(placement: .topBarLeading) { Button("Назад", action: onBack) } } .task { if mnemonic.isEmpty { mnemonic = Mnemonic.generate() } } } } private struct RestoreMnemonicView: View { let onBack: () -> Void @EnvironmentObject private var identityManager: IdentityManager @State private var mnemonicInput: String = "" @State private var error: String? var body: some View { VStack(alignment: .leading, spacing: 16) { Text("Введите 24 слова мнемоники через пробел") .font(.title3) TextEditor(text: $mnemonicInput) .font(.body.monospaced()) .frame(minHeight: 160) .border(.gray.opacity(0.4)) .autocorrectionDisabled() .textInputAutocapitalization(.never) if let error { Text(error).foregroundStyle(.red).font(.footnote) } Button { do { try identityManager.restore(from: mnemonicInput) } catch { self.error = String(describing: error) } } label: { Text("Восстановить") .frame(maxWidth: .infinity) } .buttonStyle(.borderedProminent) .controlSize(.large) .disabled(mnemonicInput.split(whereSeparator: { $0.isWhitespace }).count != 24) Spacer() } .padding() .navigationTitle("Восстановление") .toolbar { ToolbarItem(placement: .topBarLeading) { Button("Назад", action: onBack) } } } }