From cf0572a94bac73a8c21d67abfab83665a7482060 Mon Sep 17 00:00:00 2001 From: Arkadiusz Fal Date: Sat, 17 Dec 2022 15:57:59 +0100 Subject: [PATCH] Instance and account form and validation improvements --- Model/Accounts/AccountValidator.swift | 22 +++++--- Shared/Settings/AccountForm.swift | 52 ++++++++++++------- Shared/Settings/AccountValidationStatus.swift | 45 ++++++++++------ Shared/Settings/InstanceForm.swift | 43 +++++++++++---- 4 files changed, 109 insertions(+), 53 deletions(-) diff --git a/Model/Accounts/AccountValidator.swift b/Model/Accounts/AccountValidator.swift index 9da9a12d..e7a75b88 100644 --- a/Model/Accounts/AccountValidator.swift +++ b/Model/Accounts/AccountValidator.swift @@ -82,14 +82,24 @@ final class AccountValidator: Service { } guard !response.json.isEmpty else { - guard let app = self.appsToValidateInstance.popLast() else { + if app == .piped { + if response.text.contains("property=\"og:title\" content=\"Piped\"") { + self.isValid.wrappedValue = false + self.isValidated.wrappedValue = true + self.isValidating.wrappedValue = false + self.error?.wrappedValue = "Trying to use Piped front-end URL, you need to use URL for Piped API instead" + return + } + } + + guard let nextApp = self.appsToValidateInstance.popLast() else { self.isValid.wrappedValue = false self.isValidated.wrappedValue = true self.isValidating.wrappedValue = false return } - self.tryValidatingUsing(app) + self.tryValidatingUsing(nextApp) return } @@ -128,15 +138,15 @@ final class AccountValidator: Service { switch app.wrappedValue { case .invidious: - invidiousValidation() + validateInvidiousAccount() case .piped: - pipedValidation() + validatePipedAccount() default: setValidationResult(false) } } - func invidiousValidation() { + func validateInvidiousAccount() { guard let username = account?.username, let password = account?.password else { @@ -177,7 +187,7 @@ final class AccountValidator: Service { } } - func pipedValidation() { + func validatePipedAccount() { guard let request = accountRequest else { setValidationResult(false) diff --git a/Shared/Settings/AccountForm.swift b/Shared/Settings/AccountForm.swift index ca3ae6eb..8cf49e84 100644 --- a/Shared/Settings/AccountForm.swift +++ b/Shared/Settings/AccountForm.swift @@ -24,6 +24,13 @@ struct AccountForm: View { Group { header form + #if os(macOS) + VStack { + validationStatus + } + .frame(minHeight: 60, alignment: .topLeading) + .padding(.horizontal, 15) + #endif footer } .frame(maxWidth: 1000) @@ -34,7 +41,8 @@ struct AccountForm: View { .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity) .background(Color.background(scheme: colorScheme)) #else - .frame(width: 400, height: 145) + .frame(width: 400, height: 180) + .padding(.vertical) #endif } @@ -72,32 +80,36 @@ struct AccountForm: View { .onChange(of: password) { _ in validate() } } - var formFields: some View { - Group { - TextField("Username", text: $username) - SecureField("Password", text: $password) - } + @ViewBuilder var formFields: some View { + TextField("Username", text: $username) + SecureField("Password", text: $password) + + #if os(tvOS) + VStack { + validationStatus + } + .frame(minHeight: 100) + #elseif os(iOS) + validationStatus + #endif } - var usernamePrompt: String { - switch instance.app { - case .invidious: - return "SID Cookie" - default: - return "Username" + @ViewBuilder var validationStatus: some View { + if !username.isEmpty && !password.isEmpty { + Section { + AccountValidationStatus( + app: .constant(instance.app), + isValid: $isValid, + isValidated: $isValidated, + isValidating: $isValidating, + error: $validationError + ) + } } } var footer: some View { HStack { - AccountValidationStatus( - app: .constant(instance.app), - isValid: $isValid, - isValidated: $isValidated, - isValidating: $isValidating, - error: $validationError - ) - Spacer() Button("Save", action: submitForm) diff --git a/Shared/Settings/AccountValidationStatus.swift b/Shared/Settings/AccountValidationStatus.swift index f96d15b6..2e687d96 100644 --- a/Shared/Settings/AccountValidationStatus.swift +++ b/Shared/Settings/AccountValidationStatus.swift @@ -9,28 +9,41 @@ struct AccountValidationStatus: View { @Binding var error: String? var body: some View { - HStack(spacing: 4) { - Image(systemName: validationStatusSystemImage) - .foregroundColor(validationStatusColor) + VStack(alignment: .leading) { + HStack { + Image(systemName: validationStatusSystemImage) + .foregroundColor(validationStatusColor) + .imageScale(.medium) + .opacity(isValidating ? 1 : (isValidated ? 1 : 0)) - .frame(minWidth: 35, minHeight: 35) - .opacity(isValidating ? 1 : (isValidated ? 1 : 0)) - - VStack(alignment: .leading) { Text(isValid ? "Connected successfully (\(app?.name ?? "Unknown"))" : "Connection failed") - if let error, !isValid { - Text(error) - .font(.caption2) - .foregroundColor(.secondary) - .truncationMode(.tail) - .lineLimit(1) - } + .opacity(isValidated && !isValidating ? 1 : 0) + } + if errorVisible { + Text(error ?? "") + .frame(maxWidth: .infinity, alignment: .leading) + .lineLimit(nil) + .multilineTextAlignment(.leading) + .font(.footnote) + .foregroundColor(.secondary) + .padding(.top, 5) + .opacity(errorTextVisible ? 1 : 0) } - .frame(minHeight: 35) - .opacity(isValidating ? 0 : (isValidated ? 1 : 0)) } } + var errorVisible: Bool { + #if !os(iOS) + true + #else + errorTextVisible + #endif + } + + var errorTextVisible: Bool { + error != nil && isValidated && !isValid && !isValidating + } + var validationStatusSystemImage: String { if isValidating { return "bolt.horizontal.fill" diff --git a/Shared/Settings/InstanceForm.swift b/Shared/Settings/InstanceForm.swift index f229d990..a89bc737 100644 --- a/Shared/Settings/InstanceForm.swift +++ b/Shared/Settings/InstanceForm.swift @@ -22,9 +22,14 @@ struct InstanceForm: View { VStack(alignment: .leading) { Group { header - form - + #if os(macOS) + VStack { + validationStatus + } + .frame(minHeight: 60, alignment: .topLeading) + .padding(.horizontal, 15) + #endif footer } .frame(maxWidth: 1000) @@ -36,7 +41,8 @@ struct InstanceForm: View { .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity) .background(Color.background(scheme: colorScheme)) #else - .frame(width: 400, height: 150) + .frame(width: 400, height: 180) + .padding(.vertical) #endif } @@ -80,19 +86,34 @@ struct InstanceForm: View { .autocapitalization(.none) .keyboardType(.URL) #endif + + #if os(tvOS) + VStack { + validationStatus + } + .frame(minHeight: 100) + #elseif os(iOS) + validationStatus + #endif + } + } + + @ViewBuilder var validationStatus: some View { + if !url.isEmpty { + Section { + AccountValidationStatus( + app: $app, + isValid: $isValid, + isValidated: $isValidated, + isValidating: $isValidating, + error: $validationError + ) + } } } private var footer: some View { HStack { - AccountValidationStatus( - app: $app, - isValid: $isValid, - isValidated: $isValidated, - isValidating: $isValidating, - error: $validationError - ) - Spacer() Button("Save", action: submitForm)