login fix
This commit is contained in:
parent
e0190cf3bb
commit
4626b43d5e
@ -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")
|
||||||
|
|||||||
@ -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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user