Skip to content

Commit

Permalink
Quick Editor UIKit (#437)
Browse files Browse the repository at this point in the history
Co-authored-by: Pinar Olguc <[email protected]>
  • Loading branch information
etoledom and pinarol authored Oct 2, 2024
1 parent 196e134 commit c3d9a63
Show file tree
Hide file tree
Showing 12 changed files with 541 additions and 58 deletions.
191 changes: 191 additions & 0 deletions Demo/Demo/Gravatar-UIKit-Demo/DemoQuickEditorViewController.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
import UIKit
import GravatarUI

final class DemoQuickEditorViewController: UIViewController {
var savedEmail: String? {
get {
UserDefaults.standard.string(forKey: "QEEmailKey")
}
set {
UserDefaults.standard.setValue(newValue, forKey: "QEEmailKey")
}
}

var savedToken: String? {
get {
UserDefaults.standard.string(forKey: "QETokenKey")
}
set {
UserDefaults.standard.setValue(newValue, forKey: "QETokenKey")
}
}

lazy var emailField: UITextField = {
let field = UITextField()
field.translatesAutoresizingMaskIntoConstraints = false
field.textContentType = .emailAddress
field.keyboardType = .emailAddress
field.autocapitalizationType = .none
field.borderStyle = .roundedRect
field.placeholder = "email"
field.delegate = self
field.text = savedEmail
return field
}()

lazy var tokenField: UITextField = {
let field = UITextField()
let showButton = UIButton(type: .custom, primaryAction: UIAction { action in
field.isSecureTextEntry = !field.isSecureTextEntry
(action.sender as? UIButton)?.isSelected = !field.isSecureTextEntry

})
showButton.tintColor = .systemGray
showButton.setImage(UIImage(systemName: "eye"), for: .normal)
showButton.setImage(UIImage(systemName: "eye.slash"), for: .selected)

field.rightView = showButton
field.rightViewMode = .always

field.translatesAutoresizingMaskIntoConstraints = false
field.isSecureTextEntry = true

field.autocapitalizationType = .none
field.borderStyle = .roundedRect
field.placeholder = "Token (optional)"
field.text = savedToken
field.delegate = self
return field
}()

var token: String? {
guard let token = tokenField.text, !token.isEmpty else { return nil }
savedToken = token
return token
}

var selectedLayout: QELayoutOptions = .horizontal {
didSet {
layoutButton.setTitle(selectedLayout.rawValue, for: .normal)
}
}

lazy var layoutButton: UIButton = {
let button = UIButton(type: .system)
button.translatesAutoresizingMaskIntoConstraints = false
button.setTitle("Layout: \(selectedLayout.rawValue)", for: .normal)
button.addTarget(self, action: #selector(presentLayoutOptions), for: .touchUpInside)
return button
}()

@objc func presentLayoutOptions() {
let sheet = UIAlertController(title: "Layout Options", message: nil, preferredStyle: .actionSheet)
QELayoutOptions.allCases.forEach { layout in
sheet.addAction(.init(title: layout.rawValue, style: .default) { _ in
self.selectedLayout = layout
})
}
present(sheet, animated: true)
}

lazy var logoutButton: UIButton = {
let button = UIButton(type: .system)
button.translatesAutoresizingMaskIntoConstraints = false
button.setTitle("Logout", for: .normal)
button.addAction(UIAction { [weak self] _ in self?.logout() }, for: .touchUpInside)
updateLogoutButton(button)
return button
}()

func updateLogoutButton(_ button: UIButton? = nil) {
guard let savedEmail else { return }
let session = OAuthSession()
let button = button ?? logoutButton
UIView.animate {
button.isHidden = !session.hasSession(with: Email(savedEmail))
button.alpha = button.isHidden ? 0 : 1
}
}

func logout() {
guard let savedEmail else { return }
let session = OAuthSession()
session.deleteSession(with: Email(savedEmail))
updateLogoutButton()
}

lazy var showButton: UIButton = {
let button = UIButton(type: .system)
button.translatesAutoresizingMaskIntoConstraints = false
button.setTitle("Show Quick Editor", for: .normal)
button.addAction(UIAction { [weak self] _ in self?.presentQuickEditor() }, for: .touchUpInside)
button.isEnabled = savedEmail != nil
return button
}()

lazy var rootStackView: UIStackView = {
let stackView = UIStackView(arrangedSubviews: [emailField, tokenField, layoutButton, logoutButton, showButton])
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.axis = .vertical
stackView.spacing = 12
stackView.isLayoutMarginsRelativeArrangement = true
stackView.layoutMargins = .init(top: 0, left: 24, bottom: 0, right: 24)
return stackView
}()

override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBackground
view.addSubview(rootStackView)
NSLayoutConstraint.activate([
rootStackView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
rootStackView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
rootStackView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
])
}

func presentQuickEditor() {
guard let email = emailField.text else { return }
savedEmail = email
let presenter = QuickEditorPresenter(
email: Email(email),
scope: .avatarPicker,
avatarPickerConfiguration: AvatarPickerConfiguration(contentLayout: selectedLayout.contentLayout),
token: token
)

presenter.present(in: self, onDismiss: { [weak self] in
self?.updateLogoutButton()
})
}
}

extension DemoQuickEditorViewController: UITextFieldDelegate {
func textFieldDidChangeSelection(_ textField: UITextField) {
if textField == emailField {
showButton.isEnabled = Email(textField.text ?? "").isValid
}
}

func textFieldDidEndEditing(_ textField: UITextField, reason: UITextField.DidEndEditingReason) {
if textField == tokenField {
savedToken = textField.text
}
}
}

extension Email {
// This validation is not perfect, but it's intended for demo purposes only.
public var isValid: Bool {
let string = rawValue
guard string.count <= 254 else {
return false
}
let atIndex = string.lastIndex(of: "@") ?? string.endIndex
let dotIndex = string.lastIndex(of: ".") ?? string.endIndex
return (atIndex != string.startIndex)
&& (dotIndex > atIndex)
&& (string[atIndex...].count > 4)
&& (string[dotIndex...].count > 2)
}
}
5 changes: 5 additions & 0 deletions Demo/Demo/Gravatar-UIKit-Demo/MainTableViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class MainTableViewController: UITableViewController {
case profileCard
case configuration
case profileViewController
case quickEditor
#if DEBUG
case displayRemoteSVG
case imageCropper
Expand Down Expand Up @@ -55,6 +56,8 @@ class MainTableViewController: UITableViewController {
content.text = "Profile Card Configuration"
case .profileViewController:
content.text = "Profile View Controller"
case .quickEditor:
content.text = "Quick Editor"
#if DEBUG
case .displayRemoteSVG:
content.text = "Display remote SVG"
Expand Down Expand Up @@ -87,6 +90,8 @@ class MainTableViewController: UITableViewController {
show(DemoProfileConfigurationViewController(style: .insetGrouped), sender: nil)
case .profileViewController:
navigationController?.pushViewController(DemoProfilePresentationStylesViewController(), animated: true)
case .quickEditor:
navigationController?.pushViewController(DemoQuickEditorViewController(), animated: true)
#if DEBUG
case .displayRemoteSVG:
navigationController?.pushViewController(DemoRemoteSVGViewController(), animated: true)
Expand Down
6 changes: 6 additions & 0 deletions Demo/Gravatar-Demo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
1E3FA2402C74B8CC002901F2 /* Secrets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E3FA23F2C74B8CC002901F2 /* Secrets.swift */; };
1E3FA2412C74E539002901F2 /* Secrets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E3FA23F2C74B8CC002901F2 /* Secrets.swift */; };
1E3FA2452C75E403002901F2 /* DemoProfileEditorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E3FA2442C75E403002901F2 /* DemoProfileEditorView.swift */; };
1EA26DE22CA5677700AACF58 /* DemoQuickEditorViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E93D3C82CA566D90085139A /* DemoQuickEditorViewController.swift */; };
1ECAB5072BC984440043A331 /* DemoProfileConfigurationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ECAB5062BC984440043A331 /* DemoProfileConfigurationViewController.swift */; };
49018E2D2C8110C600B1207D /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 49018E2B2C8110C600B1207D /* Localizable.strings */; };
49018E2E2C8110C600B1207D /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 49018E2B2C8110C600B1207D /* Localizable.strings */; };
Expand All @@ -37,6 +38,7 @@
917DEEC92C7F639F00E43774 /* TestImageCropper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 917DEEC82C7F619100E43774 /* TestImageCropper.swift */; };
91956A522B6793AF00BF3CF0 /* SwitchWithLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91956A512B6793AF00BF3CF0 /* SwitchWithLabel.swift */; };
91956A542B67943A00BF3CF0 /* DemoUIImageViewExtensionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91956A532B67943A00BF3CF0 /* DemoUIImageViewExtensionViewController.swift */; };
919C70552CAA8A090036B03C /* QELayoutOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9133DF1A2CA54D1B0028196F /* QELayoutOptions.swift */; };
919C70572CAAF28E0036B03C /* QEColorSchemePickerRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 919C70562CAAF28E0036B03C /* QEColorSchemePickerRow.swift */; };
91B73B372C404F6E00E7D325 /* DemoAvatarPickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91B73B362C404F6E00E7D325 /* DemoAvatarPickerView.swift */; };
91E2FB042BC0276E00265E8E /* DemoProfileViewsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91E2FB032BC0276E00265E8E /* DemoProfileViewsViewController.swift */; };
Expand All @@ -51,6 +53,7 @@
1E3FA23D2C74B7B5002901F2 /* Secrets.tpl */ = {isa = PBXFileReference; lastKnownFileType = text; path = Secrets.tpl; sourceTree = "<group>"; };
1E3FA23F2C74B8CC002901F2 /* Secrets.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Secrets.swift; sourceTree = "<group>"; };
1E3FA2442C75E403002901F2 /* DemoProfileEditorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DemoProfileEditorView.swift; sourceTree = "<group>"; };
1E93D3C82CA566D90085139A /* DemoQuickEditorViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DemoQuickEditorViewController.swift; sourceTree = "<group>"; };
1ECAB5062BC984440043A331 /* DemoProfileConfigurationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DemoProfileConfigurationViewController.swift; sourceTree = "<group>"; };
3FD4781E2C50D6FD0071B8B9 /* Base.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Base.xcconfig; sourceTree = "<group>"; };
3FD478212C51D5CE0071B8B9 /* Gravatar-UIKit-Demo.Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Gravatar-UIKit-Demo.Release.xcconfig"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -204,6 +207,7 @@
914AC01F2BDAAC3C005DA4A5 /* DemoRemoteSVGViewController.swift */,
91F0B3DB2B62815F0025C4F8 /* MainTableViewController.swift */,
9133058D2C91F2C8009F5C0B /* DemoImageCropperViewController.swift */,
1E93D3C82CA566D90085139A /* DemoQuickEditorViewController.swift */,
495775EA2B5B34980082812A /* Assets.xcassets */,
495775EC2B5B34980082812A /* LaunchScreen.storyboard */,
495775EF2B5B34980082812A /* Info.plist */,
Expand Down Expand Up @@ -450,13 +454,15 @@
1E0087932B63CFFE0012ECEA /* DemoFetchProfileViewController.swift in Sources */,
1E0087952B63DBCB0012ECEA /* DemoUploadImageViewController.swift in Sources */,
495775E22B5B34970082812A /* AppDelegate.swift in Sources */,
1EA26DE22CA5677700AACF58 /* DemoQuickEditorViewController.swift in Sources */,
91956A522B6793AF00BF3CF0 /* SwitchWithLabel.swift in Sources */,
914AC01A2BD7FF08005DA4A5 /* DemoProfilePresentationStylesViewController.swift in Sources */,
91F0B3DE2B62815F0025C4F8 /* DemoAvatarDownloadViewController.swift in Sources */,
91956A542B67943A00BF3CF0 /* DemoUIImageViewExtensionViewController.swift in Sources */,
914AC0202BDAAC3C005DA4A5 /* DemoRemoteSVGViewController.swift in Sources */,
495775E42B5B34970082812A /* SceneDelegate.swift in Sources */,
1ECAB5072BC984440043A331 /* DemoProfileConfigurationViewController.swift in Sources */,
919C70552CAA8A090036B03C /* QELayoutOptions.swift in Sources */,
91E2FB042BC0276E00265E8E /* DemoProfileViewsViewController.swift in Sources */,
9133058E2C91F8D1009F5C0B /* DemoImageCropperViewController.swift in Sources */,
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"originHash" : "873e748e6cd0092c005bb2eeeb80dd830b1cffbb6a8974436ad78419281827e3",
"originHash" : "89aad130e119d7a4b1dea1ad42b23e52b29cf016999eed5d14af43b0dc276ac1",
"pins" : [
{
"identity" : "swift-snapshot-testing",
Expand Down
Loading

0 comments on commit c3d9a63

Please sign in to comment.