Skip to content

Commit

Permalink
✨ Basic form validation
Browse files Browse the repository at this point in the history
  • Loading branch information
igorkulman committed Nov 10, 2024
1 parent 1d0a554 commit 494dba4
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 26 deletions.
File renamed without changes.
20 changes: 20 additions & 0 deletions sources/Core/Sources/Core/Extensions/View+If.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//
// File.swift
// Core
//
// Created by Igor Kulman on 09.11.2024.
//

import Foundation
import SwiftUI

public extension View {
@ViewBuilder
func `if`<Content: View>(_ conditional: Bool, content: (Self) -> Content) -> some View {
if conditional {
content(self)
} else {
self
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//
// File.swift
// Features
//
// Created by Igor Kulman on 09.11.2024.
//

import Foundation

extension String {
var isValidURL: Bool {
let regEx = "((?:http|https)://)?(?:www\\.)?[\\w\\d\\-_]+\\.\\w{2,3}(\\.\\w{2})?(/(?<=/)(?:[\\w\\d\\-./_]+)?)?"
let predicate = NSPredicate(format: "SELF MATCHES %@", argumentArray: [regEx])
return predicate.evaluate(with: self)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,8 @@ final class AddSourceViewModel {
var rssUrl: String = ""
var imageUrl: String = ""

var isTitleValid: Bool {
!title.isEmpty
}

var isUrlValid: Bool {
!url.isEmpty && URL(string: url) != nil
}

var isRssUrlValid: Bool {
!rssUrl.isEmpty && URL(string: rssUrl) != nil
}

var isValid: Bool {
isTitleValid && isUrlValid && isRssUrlValid
!title.isEmpty && url.isValidURL && rssUrl.isValidURL && (imageUrl.isEmpty || imageUrl.isValidURL)
}

private let onFinished: (RssSource?) -> Void
Expand Down
17 changes: 4 additions & 13 deletions sources/Features/Sources/Features/Setup/Views/AddSourceView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,25 +21,16 @@ struct AddSourceView: View {
var body: some View {
Form {
Section(header: Text("Title", bundle: .module)) {
TextField("", text: $viewModel.title)
FormField(type: .string(required: true), text: $viewModel.title)
}
Section(header: Text("URL", bundle: .module)) {
TextField("", text: $viewModel.url)
.keyboardType(.URL)
.disableAutocorrection(true)
.autocapitalization(.none)
FormField(type: .url(required: true), text: $viewModel.url)
}
Section(header: Text("RSS URL", bundle: .module)) {
TextField("", text: $viewModel.rssUrl)
.keyboardType(.URL)
.disableAutocorrection(true)
.autocapitalization(.none)
FormField(type: .url(required: true), text: $viewModel.rssUrl)
}
Section(header: Text("Image URL (optional)", bundle: .module)) {
TextField("", text: $viewModel.imageUrl)
.keyboardType(.URL)
.disableAutocorrection(true)
.autocapitalization(.none)
FormField(type: .url(required: false), text: $viewModel.imageUrl)
}
}.navigationBarTitle(Text("Add source", bundle: .module))
.toolbar {
Expand Down
54 changes: 54 additions & 0 deletions sources/Features/Sources/Features/Setup/Views/FormField.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
//
// File.swift
// Features
//
// Created by Igor Kulman on 09.11.2024.
//

import Foundation
import SwiftUI

struct FormField: View {
enum FieldType {
case string(required: Bool)
case url(required: Bool)

var isURL: Bool {
switch self {
case .url:
return true
case .string:
return false
}
}

func validate(text: String) -> Bool {
switch self {
case let .string(required):
return !required || !text.isEmpty
case let .url(required):
return !required || text.isValidURL
}
}
}

let type: FieldType
@Binding var text: String
@State var isValid = true

var body: some View {
TextField("", text: $text, onEditingChanged: { isEditing in
if isEditing {
isValid = true
} else {
isValid = type.validate(text: text)
}
})
.foregroundColor(isValid ? .primary : .red)
.if(type.isURL) {
$0.keyboardType(.URL)
.disableAutocorrection(true)
.autocapitalization(.none)
}
}
}

0 comments on commit 494dba4

Please sign in to comment.