// // OnboardingView.swift // Nextcloud Cookbook iOS Client // // Created by Vincent Meilinger on 15.09.23. // import Foundation import OSLog import SwiftUI struct OnboardingView: View { @State var loginMethod: LoginMethod = .v2 // Login error alert @State var showAlert: Bool = false @State var alertMessage: String = String(localized: "Error: Could not connect to server.") var body: some View { ScrollView(showsIndicators: false) { VStack(spacing: 0) { Image("cookbook-icon") .resizable() .frame(width: 80, height: 80) .clipShape(RoundedRectangle(cornerRadius: 18)) .padding(.top, 48) Text("Cookbook Client") .font(.largeTitle) .bold() .padding(.top, 10) Text("Thanks for downloading! Sign in to your Nextcloud server to get started.") .font(.subheadline) .foregroundStyle(.secondary) .multilineTextAlignment(.center) .padding(.horizontal, 32) .padding(.top, 6) VStack(alignment: .leading, spacing: 16) { Picker("Login Method", selection: $loginMethod) { Text("Nextcloud Login").tag(LoginMethod.v2) Text("App Token Login").tag(LoginMethod.token) } .pickerStyle(.segmented) if loginMethod == .token { TokenLoginView( showAlert: $showAlert, alertMessage: $alertMessage ) } else if loginMethod == .v2 { V2LoginView( showAlert: $showAlert, alertMessage: $alertMessage ) } } .padding(.top, 28) } .fontDesign(.rounded) .padding() .alert(alertMessage, isPresented: $showAlert) { Button("Ok", role: .cancel) { } } } .background(Color(uiColor: .systemGroupedBackground).ignoresSafeArea()) } } protocol LoginStage { func next() -> Self func previous() -> Self } enum LoginMethod { case v2, token } enum TokenLoginStage: LoginStage { case serverAddress, userName, appToken, validate func next() -> TokenLoginStage { switch self { case .serverAddress: return .userName case .userName: return .appToken case .appToken: return .validate case .validate: return .validate } } func previous() -> TokenLoginStage { switch self { case .serverAddress: return .serverAddress case .userName: return .serverAddress case .appToken: return .userName case .validate: return .appToken } } } struct LoginLabel: View { let text: LocalizedStringKey var body: some View { Text(text) .font(.subheadline) .foregroundStyle(.secondary) } } struct BorderedLoginTextField: View { var example: LocalizedStringKey @Binding var text: String var body: some View { TextField(example, text: $text) .textFieldStyle(.plain) .autocorrectionDisabled() .textInputAutocapitalization(.never) .padding() .background(Color(uiColor: .secondarySystemGroupedBackground)) .clipShape(RoundedRectangle(cornerRadius: 10)) } } struct LoginTextField: View { var example: LocalizedStringKey @Binding var text: String var body: some View { TextField(example, text: $text) .textFieldStyle(.plain) .autocorrectionDisabled() .textInputAutocapitalization(.never) .padding() .background(Color(uiColor: .secondarySystemGroupedBackground)) .clipShape(RoundedRectangle(cornerRadius: 10)) } } struct ServerAddressField: View { @ObservedObject var userSettings = UserSettings.shared @State var serverProtocol: ServerProtocol = UserSettings.shared.serverProtocol == ServerProtocol.http.rawValue ? ServerProtocol.http : ServerProtocol.https enum ServerProtocol: String { case https="https://", http="http://" static let all = [https, http] } var body: some View { VStack(alignment: .leading, spacing: 6) { LoginLabel(text: "Server address") VStack(alignment: .leading, spacing: 10) { HStack { Picker(ServerProtocol.https.rawValue, selection: $serverProtocol) { ForEach(ServerProtocol.all, id: \.self) { Text($0.rawValue) } } .pickerStyle(.menu) .tint(.accentColor) .onChange(of: serverProtocol) { value in Logger.view.debug("\(value.rawValue)") userSettings.serverProtocol = value.rawValue } TextField("e.g.: example.com", text: $userSettings.serverAddress) .textFieldStyle(.plain) .autocorrectionDisabled() .textInputAutocapitalization(.never) .padding(10) .background(Color(uiColor: .secondarySystemGroupedBackground)) .clipShape(RoundedRectangle(cornerRadius: 8)) } Text(userSettings.serverProtocol + userSettings.serverAddress) .font(.footnote) .foregroundStyle(.secondary) } .padding() .background(Color(uiColor: .secondarySystemGroupedBackground)) .clipShape(RoundedRectangle(cornerRadius: 12)) } } } struct ServerAddressField_Preview: PreviewProvider { static var previews: some View { ServerAddressField() .previewLayout(.sizeThatFits) .padding() } }