From bf7780c50b3bee2d42063b44d6a8e00b02bb3e37 Mon Sep 17 00:00:00 2001 From: kishanraja Date: Fri, 31 Jul 2020 22:48:22 +0530 Subject: [PATCH] Add required field validation property --- .../ContentView.swift | 3 ++ .../FloatingLabelTextField.swift | 41 +++++++++++++++---- .../ObservableObject/ObservableObject.swift | 2 + 3 files changed, 39 insertions(+), 7 deletions(-) diff --git a/Example/FloatingLabelTextFieldSwiftUI/ContentView.swift b/Example/FloatingLabelTextFieldSwiftUI/ContentView.swift index 786e81b..ef428f6 100644 --- a/Example/FloatingLabelTextFieldSwiftUI/ContentView.swift +++ b/Example/FloatingLabelTextFieldSwiftUI/ContentView.swift @@ -50,6 +50,7 @@ struct ContentView: View { .addValidations([.init(condition: firstName.isValid(.alphabet), errorMessage: "Invalid Name"), .init(condition: firstName.count >= 2, errorMessage: "Minimum two character long") ]) + .isRequiredField(true, with: "Name field is required") .floatingStyle(ThemeTextFieldStyle()) .modifier(ThemeTextField()) @@ -102,6 +103,8 @@ struct ContentView: View { }) { } + .isShowError(true) + .isRequiredField(true, with: "Password field is required") .rightView({ Button(action: { withAnimation { diff --git a/Sources/FloatingLabelTextFieldSwiftUI/FloatingLabelTextField.swift b/Sources/FloatingLabelTextFieldSwiftUI/FloatingLabelTextField.swift index 9a468b1..6f28542 100644 --- a/Sources/FloatingLabelTextFieldSwiftUI/FloatingLabelTextField.swift +++ b/Sources/FloatingLabelTextFieldSwiftUI/FloatingLabelTextField.swift @@ -22,13 +22,20 @@ public struct FloatingLabelTextField: View { @Binding private var textFieldValue: String @State fileprivate var isSelected: Bool = false @Binding private var validtionChecker: Bool + private var currentError: TextFieldValidator { + if notifier.isRequiredField && isShowError && textFieldValue.isEmpty { + return TextFieldValidator(condition: false, errorMessage: notifier.requiredFieldMessage) + } + if let firstError = notifier.arrValidator.filter({!$0.condition}).first { return firstError } return TextFieldValidator(condition: true, errorMessage: "") } + @State fileprivate var isShowError: Bool = false + //MARK: Observed Object @ObservedObject private var notifier = FloatingLabelTextFieldNotifier() @@ -61,6 +68,7 @@ public struct FloatingLabelTextField: View { SecureField("", text: $textFieldValue.animation()) { } .onTapGesture { + self.isShowError = self.notifier.isRequiredField self.validtionChecker = self.currentError.condition self.editingChanged(self.isSelected) if !self.isSelected { @@ -71,6 +79,7 @@ public struct FloatingLabelTextField: View { self.isSelected = self.notifier.isSecureTextEntry currentTextField.addAction(for: .editingDidEnd) { self.isSelected = false + self.isShowError = self.notifier.isRequiredField self.commit() } } @@ -85,8 +94,10 @@ public struct FloatingLabelTextField: View { self.isSelected = isChanged self.validtionChecker = self.currentError.condition self.editingChanged(isChanged) + self.isShowError = self.notifier.isRequiredField }, onCommit: { + self.isShowError = self.notifier.isRequiredField self.validtionChecker = self.currentError.condition self.commit() }) @@ -97,6 +108,15 @@ public struct FloatingLabelTextField: View { } } + // MARK: Top error and title lable view + var topTitleLable: some View { + Text((self.currentError.condition || !notifier.isShowError) ? placeholderText : self.currentError.errorMessage) + .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: notifier.textAlignment.getAlignment()) + .animation(.default) + .foregroundColor((self.currentError.condition || !notifier.isShowError) ? (self.isSelected ? notifier.selectedTitleColor : notifier.titleColor) : notifier.errorColor) + .font(notifier.titleFont) + } + // MARK: Bottom Line View var bottomLine: some View { Divider() @@ -108,13 +128,13 @@ public struct FloatingLabelTextField: View { VStack () { ZStack(alignment: .bottomLeading) { - Text((self.currentError.condition || !notifier.isShowError) ? placeholderText : self.currentError.errorMessage) - .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: notifier.textAlignment.getAlignment()) - .animation(.default) - .foregroundColor((self.currentError.condition || !notifier.isShowError) ? (self.isSelected ? notifier.selectedTitleColor : notifier.titleColor) : notifier.errorColor) - .padding(.bottom, CGFloat(!textFieldValue.isEmpty ? notifier.spaceBetweenTitleText : 0)) - .opacity(textFieldValue.isEmpty ? 0 : 1) - .font(notifier.titleFont) + //Top error and title lable view + if notifier.isShowError && self.isShowError && textFieldValue.isEmpty { + self.topTitleLable.padding(.bottom, CGFloat(notifier.spaceBetweenTitleText)).opacity(1) + + } else { + self.topTitleLable.padding(.bottom, CGFloat(!textFieldValue.isEmpty ? notifier.spaceBetweenTitleText : 0)).opacity((textFieldValue.isEmpty) ? 0 : 1) + } HStack { // Left View @@ -303,6 +323,13 @@ extension FloatingLabelTextField { notifier.errorColor = color return self } + + /// Sets the field is required or not with message. + public func isRequiredField(_ required: Bool, with message: String) -> Self { + notifier.isRequiredField = required + notifier.requiredFieldMessage = message + return self + } } //MARK: Preview diff --git a/Sources/FloatingLabelTextFieldSwiftUI/ObservableObject/ObservableObject.swift b/Sources/FloatingLabelTextFieldSwiftUI/ObservableObject/ObservableObject.swift index 4127604..ab0133a 100644 --- a/Sources/FloatingLabelTextFieldSwiftUI/ObservableObject/ObservableObject.swift +++ b/Sources/FloatingLabelTextFieldSwiftUI/ObservableObject/ObservableObject.swift @@ -46,4 +46,6 @@ class FloatingLabelTextFieldNotifier: ObservableObject { @Published var isShowError: Bool = false @Published var errorColor: Color = .red @Published var arrValidator: [TextFieldValidator] = [] + @Published var isRequiredField: Bool = false + @Published var requiredFieldMessage: String = "" }