152 lines
3.9 KiB
Swift

//
// LoginView.swift
// BeReal
//
// Created by Javier Cicchelli on 30/11/2022.
// Copyright © 2022 Röck+Cöde. All rights reserved.
//
import SwiftUI
public struct LoginView: View {
// MARK: States
@State private var containerTopPadding: CGFloat = 0
// MARK: Initialisers
public init() {}
// MARK: Body
public var body: some View {
ScrollView(
.vertical,
showsIndicators: false
) {
LoginContainer()
.padding(.horizontal, 24)
.padding(.top, containerTopPadding)
}
.background(Color.red)
.overlay(ViewHeightGeometry())
.onPreferenceChange(ViewHeightPreferenceKey.self) { height in
containerTopPadding = height * 0.1
}
}
}
// MARK: - Views
fileprivate extension LoginView {
struct LoginContainer: View {
// MARK: States
@State private var isAuthenticating: Bool = false
@State private var username: String = ""
@State private var password: String = ""
@State private var errorMessage: String?
// MARK: Body
var body: some View {
VStack(spacing: 32) {
Text("login.title.text", bundle: .module)
.font(.largeTitle)
.fontWeight(.bold)
.foregroundColor(.primary)
LoginForm(
username: $username,
password: $password,
errorMessage: $errorMessage
) {
// TODO: login with the username and password.
}
Button {
// TODO: login with the username and password.
} label: {
Label {
Text("login.button.log_in.text", bundle: .module)
.fontWeight(.semibold)
} icon: {
if isAuthenticating {
ProgressView()
} else {
EmptyView()
}
}
.labelStyle(LogInLabelStyle())
}
.tint(.orange)
.buttonStyle(.borderedProminent)
.buttonBorderShape(.roundedRectangle(radius: 8))
.controlSize(.large)
.disabled(isLoginDisabled)
}
}
}
struct ViewHeightGeometry: View {
var body: some View {
GeometryReader { proxy in
Color.clear.preference(
key: ViewHeightPreferenceKey.self,
value: proxy.size.height + proxy.safeAreaInsets.top + proxy.safeAreaInsets.bottom
)
}
}
}
}
// MARK: - Label styles
private extension LoginView.LoginContainer {
struct LogInLabelStyle: LabelStyle {
func makeBody(configuration: Configuration) -> some View {
HStack(spacing: 8) {
Spacer()
configuration.title
.font(.body)
.foregroundColor(.primary)
configuration.icon
.tint(.primary)
Spacer()
}
}
}
}
// MARK: - Helpers
private extension LoginView.LoginContainer {
var isLoginDisabled: Bool {
username.isEmpty || password.isEmpty
}
}
// MARK: - Preference keys
struct ViewHeightPreferenceKey: PreferenceKey {
static var defaultValue: CGFloat = 0
static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
value = nextValue()
}
}
// MARK: - Previews
struct LoginView_Previews: PreviewProvider {
static var previews: some View {
LoginView()
}
}