/** * TrackerMap * Copyright (C) 2021-2022 Iván Ávalos , Henoch Ojeda * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ import SwiftUI import shared class SessionState: ObservableObject { @Published var loggedIn = false } struct RootView: View { @StateObject private var rootViewModel = RootViewModel() @State private var username = "" @State private var password = "" @State private var server: String init() { server = UserDefaults.standard.string(forKey: "server-url") ?? NSLocalizedString("app-server-url", comment: "") } var body: some View { Group { switch rootViewModel.loginState { case is SessionController.LoginStateLoading: LoadingView() case is SessionController.LoginStateSuccess: UnitsView() default: LoginContentView(username: $username, password: $password, server: $server, onLogin: rootViewModel.login) } }.environmentObject(rootViewModel) } } struct LoginContentView: View { @Binding var username: String @Binding var password: String @Binding var server: String let onLogin: (String, String, String) -> Void var body: some View { VStack { Spacer() LoginTitleView() Spacer() LoginForm(username: $username, password: $password, server: $server) Button(action: { self.onLogin(username, password, server) }) { Text("login") .font(.system(size: 18)) .bold() } .padding([.top, .bottom], 30) Spacer() } .padding() } } // Source: https://github.com/niochat/nio struct LoginTitleView: View { var body: some View { return VStack { Text("app-name") .font(.title) .bold() } } } struct LoginForm: View { @Binding var username: String @Binding var password: String @Binding var server: String var body: some View { VStack { FormTextField(title: "username", text: $username) FormTextField(title: "password", text: $password, isSecure: true) #if os(macOS) FormTextField(title: "server-url", text: $server) .visible(false) #else FormTextField(title: "server-url", text: $server, keyboardType: .URL) .visible(false) #endif } } } private struct FormTextField: View { @Environment(\.colorScheme) private var colorScheme let title: LocalizedStringKey @Binding var text: String var onEditingChanged: ((Bool) -> Void)? #if os(macOS) #else var keyboardType: UIKeyboardType = .default #endif var isSecure = false var body: some View { ZStack { Capsule(style: .continuous) .foregroundColor(colorScheme == .light ? Color(#colorLiteral(red: 0.9395676295, green: 0.9395676295, blue: 0.9395676295, alpha: 1)) : Color(#colorLiteral(red: 0.2293992357, green: 0.2293992357, blue: 0.2293992357, alpha: 1))) .frame(height: 50) if isSecure { SecureField(title, text: $text) .padding() .textContentType(.password) } else { #if os(macOS) TextField(title, text: $text, onEditingChanged: onEditingChanged ?? { _ in }) .padding() .autocapitalization(.none) .disableAutocorrection(true) #else TextField(title, text: $text, onEditingChanged: onEditingChanged ?? { _ in }) .padding() .autocapitalization(.none) .disableAutocorrection(true) .keyboardType(keyboardType) #endif } } .padding(.horizontal) .frame(maxWidth: 400) } }