// // 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() } }