// // LoginView.swift // medmap // import SwiftUI struct LoginView: View { @StateObject private var viewModel = LoginViewModel() @FocusState private var focusedField: Field? private enum Field { case email case password } var body: some View { ZStack { Color.appBackground.ignoresSafeArea() formPanel } //.preferredColorScheme(.light) } private var brandPanel: some View { ZStack(alignment: .bottomLeading) { Color.appBackground.ignoresSafeArea() Image("splashImage") .resizable() .scaledToFit() .frame(maxWidth: 360) .padding(40) .accessibilityHidden(true) VStack(alignment: .leading, spacing: 10) { Image("splashLogo") .resizable() .scaledToFit() .frame(width: 146, height: 96) .accessibilityHidden(true) Text("MedMap") .font(.jakartaBold24) .foregroundStyle(.white) Text("Acompanhamento simples da sua medicacao.") .font(.jakartaRegular16) .foregroundStyle(.white.opacity(0.84)) .fixedSize(horizontal: false, vertical: true) } .padding(44) } .ignoresSafeArea() } private var formPanel: some View { VStack(spacing: 0) { Spacer(minLength: 32) VStack(alignment: .leading, spacing: 28) { VStack(alignment: .leading, spacing: 10) { if UIDevice.current.userInterfaceIdiom == .phone { Image("splashLogo") .resizable() .scaledToFit() .frame(width: 120, height: 76) .accessibilityHidden(true) } Text("Bem-vindo de volta") .font(.jakartaBold24) .foregroundStyle(Color.appTextPrimary) } VStack(spacing: 18) { loginField( title: "Email", placeholder: "Email", icon: "envelope", text: $viewModel.email, field: .email, contentType: .emailAddress, keyboardType: .emailAddress ) passwordField } if let errorMessage = viewModel.errorMessage { Text(errorMessage) .font(.jakartaRegular14) .foregroundStyle(.red) .fixedSize(horizontal: false, vertical: true) .accessibilityLabel("Erro de autenticacao: \(errorMessage)") } Button { focusedField = nil Task { await viewModel.login() } } label: { Group { if viewModel.isLoading { ProgressView() .tint(.white) } else { Text("Entrar") .font(.jakartaBold16) } } .frame(maxWidth: .infinity) .frame(height: 52) } .clipShape(RoundedRectangle(cornerRadius: 8)) .disabled(!viewModel.canSubmit) .opacity(viewModel.canSubmit ? 1 : 0.55) .accessibilityHint("Inicia sessao na conta de doente") } .padding(.horizontal, 32) Spacer() Text("MedMap") .font(.jakartaRegular12) .foregroundStyle(Color.appTextPrimary.opacity(0.45)) .padding(.bottom, 24) } } private var passwordField: some View { VStack(alignment: .leading, spacing: 8) { Text("Palavra-passe") .font(.jakartaMedium14) .foregroundStyle(Color.appTextPrimary) HStack(spacing: 12) { Image(systemName: "lock") .foregroundStyle(Color.appBackground) .frame(width: 20) SecureField("Palavra-passe", text: $viewModel.password) .textContentType(.password) .focused($focusedField, equals: .password) .submitLabel(.go) .onSubmit { Task { await viewModel.login() } } } .padding(.horizontal, 16) .frame(height: 52) .background(Color.appSecondary) .overlay { RoundedRectangle(cornerRadius: 8) .stroke(Color.appBorder, lineWidth: 1) } .clipShape(RoundedRectangle(cornerRadius: 8)) } } private func loginField( title: String, placeholder: String, icon: String, text: Binding, field: Field, contentType: UITextContentType, keyboardType: UIKeyboardType ) -> some View { VStack(alignment: .leading, spacing: 8) { Text(title) .font(.jakartaMedium14) .foregroundStyle(Color.appTextPrimary) HStack(spacing: 12) { Image(systemName: icon) .foregroundStyle(Color.appBackground) .frame(width: 20) TextField(placeholder, text: text) .textContentType(contentType) .keyboardType(keyboardType) .textInputAutocapitalization(.never) .autocorrectionDisabled() .focused($focusedField, equals: field) .submitLabel(.next) .onSubmit { focusedField = .password } } .padding(.horizontal, 16) .frame(height: 52) .background(Color.appSecondary) .overlay { RoundedRectangle(cornerRadius: 8) .stroke(Color.appBorder, lineWidth: 1) } .clipShape(RoundedRectangle(cornerRadius: 8)) } } } #Preview { LoginView() }