login fix

This commit is contained in:
Ricardo Araújo 2026-09-15 15:46:57 +01:00
parent e0190cf3bb
commit 4626b43d5e
2 changed files with 69 additions and 54 deletions

View File

@ -57,6 +57,14 @@ extension Color {
static let appTextPrimary = Color(hex: "#333333") static let appTextPrimary = Color(hex: "#333333")
static let appBorder = Color(hex: "#E5E5E5") static let appBorder = Color(hex: "#E5E5E5")
// MARK: - Login screen (matches src/main/resources/static/css/login.css)
static let loginFieldBackground = Color(hex: "#5D8CC6")
static let loginFieldBorder = Color.white.opacity(0.45)
static let loginPlaceholder = Color.white.opacity(0.6)
static let loginButtonBackground = Color(hex: "#88BDFF")
static let loginButtonText = Color(hex: "#0A2647")
static let loginErrorText = Color(hex: "#FFE08A")
// Add more as needed, e.g.: // Add more as needed, e.g.:
// static let appError = Color(hex: "#FF3B30") // static let appError = Color(hex: "#FF3B30")
// static let appSuccess = Color(hex: "#34C759") // static let appSuccess = Color(hex: "#34C759")

View File

@ -61,10 +61,9 @@ struct LoginView: View {
private var formPanel: some View { private var formPanel: some View {
VStack(spacing: 0) { VStack(spacing: 0) {
Spacer(minLength: 32) Spacer(minLength: 32)
VStack(alignment: .leading, spacing: 28) { VStack(alignment: .leading, spacing: 24) {
VStack(alignment: .leading, spacing: 10) { VStack(alignment: .leading, spacing: 10) {
if UIDevice.current.userInterfaceIdiom == .phone { if UIDevice.current.userInterfaceIdiom == .phone {
Image("splashLogo") Image("splashLogo")
@ -74,15 +73,13 @@ struct LoginView: View {
.accessibilityHidden(true) .accessibilityHidden(true)
} }
Text("Bem-vindo de volta") Text("Aceda aqui à sua conta")
.font(.jakartaBold24) .font(.jakartaBold24)
.foregroundStyle(Color.appTextPrimary) .foregroundStyle(.white)
} }
VStack(spacing: 18) { VStack(spacing: 14) {
loginField( loginField(
title: "Email",
placeholder: "Email", placeholder: "Email",
icon: "envelope", icon: "envelope",
text: $viewModel.email, text: $viewModel.email,
@ -97,7 +94,9 @@ struct LoginView: View {
if let errorMessage = viewModel.errorMessage { if let errorMessage = viewModel.errorMessage {
Text(errorMessage) Text(errorMessage)
.font(.jakartaRegular14) .font(.jakartaRegular14)
.foregroundStyle(.red) .foregroundStyle(Color.loginErrorText)
.frame(maxWidth: .infinity)
.multilineTextAlignment(.center)
.fixedSize(horizontal: false, vertical: true) .fixedSize(horizontal: false, vertical: true)
.accessibilityLabel("Erro de autenticacao: \(errorMessage)") .accessibilityLabel("Erro de autenticacao: \(errorMessage)")
} }
@ -111,46 +110,49 @@ struct LoginView: View {
Group { Group {
if viewModel.isLoading { if viewModel.isLoading {
ProgressView() ProgressView()
.tint(.white) .tint(Color.loginButtonText)
} else { } else {
Text("Entrar") Text("Entrar")
.font(.jakartaBold16) .font(.jakartaBold16)
} }
} }
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
.frame(height: 52) .frame(height: 46)
} }
.foregroundStyle(Color.loginButtonText)
.background(Color.loginButtonBackground)
.clipShape(RoundedRectangle(cornerRadius: 8)) .clipShape(RoundedRectangle(cornerRadius: 8))
.disabled(!viewModel.canSubmit) .disabled(!viewModel.canSubmit)
.opacity(viewModel.canSubmit ? 1 : 0.55) .opacity(viewModel.canSubmit ? 1 : 0.55)
.accessibilityHint("Inicia sessao na conta de doente") .accessibilityHint("Inicia sessao na conta de doente")
}
Text("Não tem conta? Criar conta")
.font(.jakartaRegular14)
.foregroundStyle(.white.opacity(0.88))
.frame(maxWidth: .infinity)
.multilineTextAlignment(.center)
}
.padding(.horizontal, 32) .padding(.horizontal, 32)
Spacer() Spacer()
Text("MedMap") Text("MedMap")
.font(.jakartaRegular12) .font(.jakartaRegular12)
.foregroundStyle(Color.appTextPrimary.opacity(0.45)) .foregroundStyle(.white.opacity(0.6))
.padding(.bottom, 24) .padding(.bottom, 24)
} }
} }
private var passwordField: some View { private var passwordField: some View {
VStack(alignment: .leading, spacing: 8) { loginFieldContainer(icon: "lock") {
Text("Palavra-passe") ZStack(alignment: .leading) {
.font(.jakartaMedium14) if viewModel.password.isEmpty {
.foregroundStyle(Color.appTextPrimary) Text("Palavra-passe")
.foregroundStyle(Color.loginPlaceholder)
HStack(spacing: 12) { }
Image(systemName: "lock") SecureField("", text: $viewModel.password)
.foregroundStyle(Color.appBackground) .foregroundStyle(.white)
.frame(width: 20) .tint(.white)
SecureField("Palavra-passe", text: $viewModel.password)
.textContentType(.password) .textContentType(.password)
.focused($focusedField, equals: .password) .focused($focusedField, equals: .password)
.submitLabel(.go) .submitLabel(.go)
@ -160,19 +162,11 @@ struct LoginView: View {
} }
} }
} }
.padding(.horizontal, 16)
.frame(height: 52)
.background(Color.appSecondary)
.overlay {
RoundedRectangle(cornerRadius: 8)
.stroke(Color.appBorder, lineWidth: 1)
}
.clipShape(RoundedRectangle(cornerRadius: 8))
} }
.accessibilityLabel("Palavra-passe")
} }
private func loginField( private func loginField(
title: String,
placeholder: String, placeholder: String,
icon: String, icon: String,
text: Binding<String>, text: Binding<String>,
@ -180,16 +174,15 @@ struct LoginView: View {
contentType: UITextContentType, contentType: UITextContentType,
keyboardType: UIKeyboardType keyboardType: UIKeyboardType
) -> some View { ) -> some View {
VStack(alignment: .leading, spacing: 8) { loginFieldContainer(icon: icon) {
Text(title) ZStack(alignment: .leading) {
.font(.jakartaMedium14) if text.wrappedValue.isEmpty {
.foregroundStyle(Color.appTextPrimary) Text(placeholder)
.foregroundStyle(Color.loginPlaceholder)
HStack(spacing: 12) { }
Image(systemName: icon) TextField("", text: text)
.foregroundStyle(Color.appBackground) .foregroundStyle(.white)
.frame(width: 20) .tint(.white)
TextField(placeholder, text: text)
.textContentType(contentType) .textContentType(contentType)
.keyboardType(keyboardType) .keyboardType(keyboardType)
.textInputAutocapitalization(.never) .textInputAutocapitalization(.never)
@ -200,15 +193,29 @@ struct LoginView: View {
focusedField = .password focusedField = .password
} }
} }
.padding(.horizontal, 16)
.frame(height: 52)
.background(Color.appSecondary)
.overlay {
RoundedRectangle(cornerRadius: 8)
.stroke(Color.appBorder, lineWidth: 1)
}
.clipShape(RoundedRectangle(cornerRadius: 8))
} }
.accessibilityLabel(placeholder)
}
private func loginFieldContainer<Content: View>(
icon: String,
@ViewBuilder content: () -> Content
) -> some View {
HStack(spacing: 10) {
Image(systemName: icon)
.foregroundStyle(.white)
.frame(width: 18)
content()
.font(.jakartaRegular16)
}
.padding(.horizontal, 14)
.frame(height: 46)
.background(Color.loginFieldBackground)
.overlay {
RoundedRectangle(cornerRadius: 8)
.stroke(Color.loginFieldBorder, lineWidth: 1)
}
.clipShape(RoundedRectangle(cornerRadius: 8))
} }
} }