Add current state of binding reactor demo

This commit is contained in:
Ira Limitanei 2024-06-14 18:03:09 +09:00
parent fa714a2331
commit a4057884da
No known key found for this signature in database
GPG Key ID: 3B416C2117091FF3

View File

@ -0,0 +1,182 @@
//
// BindingReactorDemo.swift
// Adwaita
//
// Created by lambdaclan on 13.06.24.
//
// swiftlint:disable missing_docs no_magic_numbers
import Adwaita
enum PasswordChecker: String, CaseIterable, CustomStringConvertible, Identifiable {
case length
case upper
var id: String {
self.rawValue
}
var label: String {
switch self {
case .length:
return "Password Length"
case .upper:
return "Password Uppercase Characters"
}
}
var description: String {
switch self {
case .length:
return "Password needs to be greater than 8 characters long"
case .upper:
return "Password needs to contain at least one uppercase character"
}
}
}
struct BindingReactorDemo: View {
var app: GTUIApp
var view: Body {
VStack {
Button("View Demo") {
app.showWindow("binding-reactor-demo")
}
.suggested()
.pill()
.frame(maxWidth: 100)
}
}
struct WindowContent: View {
@State private var password = ""
@State var checkStatus = PasswordChecker.allCases.enumerated().reduce([String: Bool]()) { dict, checker in
var dict = dict
dict[checker.element.rawValue] = false
return dict
}
var view: Body {
VStack {
FormSection("Password Checker") {
Form {
EntryRow("Password", text: $password.onSet { _ in
Task {
let results = await checkPassword(content: password)
Idle {
for result in results {
checkStatus[result.0] = result.1
}
}
}
})
}
}
.padding()
ForEach(PasswordChecker.allCases) { checker in
CheckerButton(
isValid: binding(for: checker.rawValue),
checkerName: checker.label,
checkerInfo: checker.description
)
.padding()
}
}
.padding()
.frame(minWidth: 340, minHeight: 400)
.topToolbar {
HeaderBar.empty()
}
}
private func binding(for key: String) -> Binding<Bool> {
.init {
checkStatus[key] ?? false
} set: { newValue in
checkStatus[key] = newValue
}
}
private func checkPassword(content password: String) async -> [(String, Bool)] {
var results: [(String, Bool)] = []
await withTaskGroup(of: (String, Bool).self) { group in
for checker in PasswordChecker.allCases {
group.addTask {
await check(password: password, checker: checker)
}
}
for await result in group {
results.append(result)
}
}
return results
}
private func check(password: String, checker: PasswordChecker) async -> (String, Bool) {
switch checker {
case .length:
return (PasswordChecker.length.rawValue, password.count > 8)
case .upper:
let result = password.range(of: ".*[A-Z]+.*", options: .regularExpression)
return (PasswordChecker.upper.rawValue, result != nil ? true : false)
}
}
}
private struct CheckerButton: View {
@Binding var isValid: Bool
@State var isInfoVisible = false
var checkerName: String
var checkerInfo: String
var view: Body {
if isValid {
Button("") {
isInfoVisible = true
}
.child {
ButtonContent()
.iconName(Icon.DefaultIcon.emblemOk.string)
.label(checkerName)
.halign(.start)
}
.success()
.alertDialog(
visible: $isInfoVisible,
heading: checkerName,
body: checkerInfo
)
.response("OK", role: .close) {}
} else {
Button("") {
isInfoVisible = true
}
.child {
ButtonContent()
.iconName(Icon.DefaultIcon.faceAngry.string)
.label(checkerName)
.halign(.start)
}
.destructive()
.alertDialog(
visible: $isInfoVisible,
heading: checkerName,
body: checkerInfo
)
.response("OK", role: .close) {}
}
}
}
}
// swiftlint:enable missing_docs no_magic_numbers