Skip to content

Commit

Permalink
Merge pull request #10 from brunomunizaf/dev
Browse files Browse the repository at this point in the history
Use NSAttributedString on titles, subtitles and placeholders
  • Loading branch information
brunomunizaf authored Oct 25, 2023
2 parents c3f119d + 6c22f20 commit f96d0f9
Show file tree
Hide file tree
Showing 22 changed files with 553 additions and 470 deletions.
8 changes: 8 additions & 0 deletions Example/Example.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
321F5CFD2ACA4D3100FB8AC5 /* PersonalScreenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 321F5CFC2ACA4D3100FB8AC5 /* PersonalScreenView.swift */; };
322788552AC35D0F00F16F06 /* ValidatableFormItems.swift in Sources */ = {isa = PBXBuildFile; fileRef = 322788542AC35D0F00F16F06 /* ValidatableFormItems.swift */; };
322B458E2AC33BEB001917DE /* Forms in Frameworks */ = {isa = PBXBuildFile; productRef = 322B458D2AC33BEB001917DE /* Forms */; };
32BC643F2AE78924000A528B /* ReusableStyles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32BC643E2AE78924000A528B /* ReusableStyles.swift */; };
32BC64412AE78F53000A528B /* Strings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32BC64402AE78F53000A528B /* Strings.swift */; };
32EF92582ACA5934002278A7 /* PermissionsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32EF92572ACA5934002278A7 /* PermissionsViewController.swift */; };
32EF925A2ACA595C002278A7 /* PermissionsScreenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32EF92592ACA595C002278A7 /* PermissionsScreenView.swift */; };
32EF925C2ACA5FD7002278A7 /* FinishedViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32EF925B2ACA5FD7002278A7 /* FinishedViewController.swift */; };
Expand All @@ -37,6 +39,8 @@
321F5CFA2ACA4D0A00FB8AC5 /* PersonalViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PersonalViewController.swift; sourceTree = "<group>"; };
321F5CFC2ACA4D3100FB8AC5 /* PersonalScreenView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PersonalScreenView.swift; sourceTree = "<group>"; };
322788542AC35D0F00F16F06 /* ValidatableFormItems.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValidatableFormItems.swift; sourceTree = "<group>"; };
32BC643E2AE78924000A528B /* ReusableStyles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReusableStyles.swift; sourceTree = "<group>"; };
32BC64402AE78F53000A528B /* Strings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Strings.swift; sourceTree = "<group>"; };
32EF92572ACA5934002278A7 /* PermissionsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PermissionsViewController.swift; sourceTree = "<group>"; };
32EF92592ACA595C002278A7 /* PermissionsScreenView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PermissionsScreenView.swift; sourceTree = "<group>"; };
32EF925B2ACA5FD7002278A7 /* FinishedViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FinishedViewController.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -83,6 +87,8 @@
321225CC2AC33A5700DBE7E9 /* LaunchScreen.storyboard */,
321225CF2AC33A5700DBE7E9 /* Info.plist */,
322788542AC35D0F00F16F06 /* ValidatableFormItems.swift */,
32BC643E2AE78924000A528B /* ReusableStyles.swift */,
32BC64402AE78F53000A528B /* Strings.swift */,
);
path = Example;
sourceTree = "<group>";
Expand Down Expand Up @@ -193,9 +199,11 @@
321F5CFB2ACA4D0A00FB8AC5 /* PersonalViewController.swift in Sources */,
32EF925A2ACA595C002278A7 /* PermissionsScreenView.swift in Sources */,
321F5CF92ACA4ADC00FB8AC5 /* TermsScreenView.swift in Sources */,
32BC64412AE78F53000A528B /* Strings.swift in Sources */,
322788552AC35D0F00F16F06 /* ValidatableFormItems.swift in Sources */,
321F5CF62ACA477A00FB8AC5 /* TermsViewController.swift in Sources */,
32EF925E2ACA6006002278A7 /* FinishedScreenView.swift in Sources */,
32BC643F2AE78924000A528B /* ReusableStyles.swift in Sources */,
321225C42AC33A5600DBE7E9 /* SceneDelegate.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down
28 changes: 22 additions & 6 deletions Example/Example/Controllers/PermissionsViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,28 +41,44 @@ final class PermissionsViewController: UIViewController {
/// Subscribes to `.valueChangedPublisher` from custom extension
/// located at `UIControl+Publishers.swift`
screenView
.firstSwitchItem
.locationSwitchItem
.isOnPublisher
.receive(on: DispatchQueue.main)
.sink { print(">>> 1st FormSwitchItem \($0 ? "on" : "off")") }
.sink { [unowned self] in
print(">>> 1st FormSwitchItem \($0 ? "on" : "off")")
validateForm()
}
.store(in: &cancellables)

/// Subscribes to `.valueChangedPublisher` from custom extension
/// located at `UIControl+Publishers.swift`
screenView
.secondSwitchItem
.notificationsSwitchItem
.isOnPublisher
.receive(on: DispatchQueue.main)
.sink { print(">>> 2nd FormSwitchItem \($0 ? "on" : "off")") }
.sink { [unowned self] in
print(">>> 2nd FormSwitchItem \($0 ? "on" : "off")")
validateForm()
}
.store(in: &cancellables)

/// Subscribes to `.valueChangedPublisher` from custom extension
/// located at `UIControl+Publishers.swift`
screenView
.thirdSwitchItem
.cameraSwitchItem
.isOnPublisher
.receive(on: DispatchQueue.main)
.sink { print(">>> 3rd FormSwitchItem \($0 ? "on" : "off")") }
.sink { [unowned self] in
print(">>> 3rd FormSwitchItem \($0 ? "on" : "off")")
validateForm()
}
.store(in: &cancellables)
}

// MARK: - Validation

/// Validates the form and updates the UI accordingly.
func validateForm() {
screenView.buttonItem.isEnabled = screenView.formView.isValid
}
}
12 changes: 6 additions & 6 deletions Example/Example/Controllers/PersonalViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,21 +29,21 @@ final class PersonalViewController: UIViewController {

/// Sets up target-action for buttons and other UI components.
private func setupActions() {
screenView.inputItem.didChange = { [weak self] in
screenView.addressItem.didChange = { [weak self] in
if let text = $0 {
print(">>> 'inputItem' = \(text)")
print(">>> 'addressItem' = \(text)")
}
self?.validateForm()
}
screenView.numbersInputItem.didChange = { [weak self] in
screenView.phoneItem.didChange = { [weak self] in
if let text = $0 {
print(">>> 'numbersInputItem' = \(text)")
print(">>> 'phoneItem' = \(text)")
}
self?.validateForm()
}
screenView.requiredInputItem.didChange = { [weak self] in
screenView.nameItem.didChange = { [weak self] in
if let text = $0 {
print(">>> 'requiredInputItem' = \(text)")
print(">>> 'nameItem' = \(text)")
}
self?.validateForm()
}
Expand Down
175 changes: 175 additions & 0 deletions Example/Example/ReusableStyles.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
import Forms
import UIKit

// MARK: - FormInputItem

extension FormInputItem.Configuration {
static func with(
title: String,
placeholder: String
) -> FormInputItem.Configuration {
FormInputItem.Configuration(
title: [
NSAttributedString(
string: title,
attributes: [
.font: UIFont(name: "AvenirNext-Medium", size: 16)!,
.foregroundColor: UIColor.label
])
],
initialText: nil,
placeholder: [
NSAttributedString(
string: placeholder,
attributes: [
.foregroundColor: UIColor.tertiaryLabel,
.font: UIFont(name: "AvenirNext-Regular", size: 16)!
])
],
isSecure: false,
autocorrectionType: .no,
autocapitalizationType: .none,
font: UIFont(name: "AvenirNext-Regular", size: 16)!,
textColor: UIColor.label,
cornerRadius: 8,
borderWidth: 1.0,
borderColor: UIColor.systemGray,
spacingAfter: 15,
didChange: nil
)
}
}


// MARK: - FormSwitchItem

extension FormSwitchItem.Configuration {
static func with(
title: String,
subtitle: String
) -> FormSwitchItem.Configuration {
FormSwitchItem.Configuration(
title: [
NSAttributedString(
string: title,
attributes: [
.foregroundColor: UIColor.label,
.font: UIFont(name: "AvenirNext-Medium", size: 17)!
])
],
subtitle: [
NSAttributedString(
string: subtitle,
attributes: [
.foregroundColor: UIColor.secondaryLabel,
.font: UIFont(name: "AvenirNext-Regular", size: 15)!
])
],
onColor: .systemBlue,
isOn: false,
spacingAfter: 25
)
}
}

// MARK: FormCheckboxItem

extension FormCheckboxItem.Configuration {
static func with(
title: String,
subtitle: String,
highlightedSubtitle: String
) -> FormCheckboxItem.Configuration {
FormCheckboxItem.Configuration(
title: [
NSAttributedString(
string: title,
attributes: [
.foregroundColor: UIColor.label,
.font: UIFont(name: "AvenirNext-Medium", size: 18)!
])
],
subtitle: [
NSAttributedString(
string: subtitle,
attributes: [
.foregroundColor: UIColor.secondaryLabel,
.font: UIFont(name: "AvenirNext-Regular", size: 14)!
]),
NSAttributedString(
string: highlightedSubtitle,
attributes: [
.foregroundColor: UIColor.secondaryLabel,
.underlineStyle: NSUnderlineStyle.single.rawValue,
.font: UIFont(name: "AvenirNext-Regular", size: 14)!
])
],
checkedColor: UIColor.systemGreen,
uncheckedColor: UIColor.white,
borderWidth: 1.0,
borderColor: UIColor.lightGray,
cornerRadius: 5.0,
isChecked: false,
spacingAfter: 20.0,
shouldBeSelected: false
)
}
}

// MARK: FormTextItem

extension FormTextItem.Configuration {
static func h1(_ title: String) -> FormTextItem.Configuration {
FormTextItem.Configuration(
text: [
NSAttributedString(
string: title,
attributes: [
.font: UIFont(name: "AvenirNext-DemiBold", size: 24)!,
.foregroundColor: UIColor.label,
.kern: 0.5
])
],
spacingAfter: 20
)
}

static func h2(_ title: String) -> FormTextItem.Configuration {
FormTextItem.Configuration(
text: [
NSAttributedString(
string: title,
attributes: [
.font: UIFont(name: "AvenirNext-Regular", size: 16)!,
.foregroundColor: UIColor.secondaryLabel,
.kern: 0.2
])
],
spacingAfter: 20
)
}
}

// MARK: FormButtonItem

extension FormButtonItem.Configuration {
static func withTitle(_ title: String) -> FormButtonItem.Configuration {
FormButtonItem.Configuration(
title: [
NSAttributedString(
string: title,
attributes: [
.font: UIFont(name: "AvenirNext-Bold", size: 20)!,
.foregroundColor: UIColor.white
])
],
enabledColor: UIColor.systemBlue,
disabledColor: UIColor.systemGray,
borderWidth: 1.0,
borderColor: UIColor.clear,
cornerRadius: 10.0,
spacingAfter: 0,
shouldBeEnabled: false
)
}
}
40 changes: 40 additions & 0 deletions Example/Example/Strings.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
enum Strings {
enum Personal {
static let title = "Your personal details"
static let subtitle = "Insert your personal information to keep your profile up to date."
static let addressTitle = "Street Address"
static let addressPlaceholder = "e.g. 5912 5th Avenue, New York, NY"
static let nameTitle = "Full Name"
static let namePlaceholder = "Required"
static let phoneTitle = "Phone Number"
static let phonePlaceholder = "Only numbers allowed"
static let calendarTitle = "Date of Birth"
static let button = "Continue to Permissions"
}

enum Permissions {
static let title = "Manage Permissions"
static let subtitle = "Customize which features the app can access to enhance your user experience."
static let locationTitle = "Location Access"
static let locationSubtitle = "Allow the app to access your location to enhance service delivery and improve user experience."
static let notificationsTitle = "Notifications"
static let notificationsSubtitleA = "Enable notifications to stay updated with the latest news, updates, and offers.\n"
static let notificationsSubtitleB = "Enabling this permission is required."
static let cameraTitle = "Camera Access"
static let cameraSubtitle = "Grant permission to access your camera to take photos and videos within the app."
static let button = "Continue to T&C"
}

enum Terms {
static let title = "Review Our Terms & Conditions"
static let subtitle = "Please read carefully to understand your rights and obligations while using our services."
static let checkboxTitle = "Acceptance of Terms & Conditions"
static let checkboxSubtitle = "By checking this box, "
static let checkboxSubtitleHighlighted = "you acknowledge that you have read, understood, and agree to abide by the terms and conditions outlined above."
static let button = "Continue to Registration"
}

enum Finished {
static let title = "Horray! You finished the onboarding. 🎉"
}
}
13 changes: 11 additions & 2 deletions Example/Example/ValidatableFormItems.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,15 @@ final class RegexFormInputItem: FormInputItem, Validatable {
/// `RequiredFormCheckboxItem` is a subclass of `FormCheckboxItem` and conforms to `Validatable`.
/// It considers the item valid if it is selected.
final class RequiredFormCheckboxItem: FormCheckboxItem, Validatable {
/// A computed property to check if the checkbox item is selected and therefore valid.
var isValid: Bool { isSelected }

/// A computed property to check if the value is valid.
var isValid: Bool { value == true }
}

/// `RequiredFormSwitchItem` is a subclass of `FormSwitchItem` and conforms to `Validatable`.
/// It considers the item valid if it is enabled.
final class RequiredFormSwitchItem: FormSwitchItem, Validatable {

/// A computed property to check if the value is valid.
var isValid: Bool { value == true }
}
16 changes: 1 addition & 15 deletions Example/Example/Views/FinishedScreenView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ final class FinishedScreenView: UIView {
// MARK: - Properties

let formView = FormView(elements: [
FormTextItem(configuration: .title)
FormTextItem(configuration: .h1(Strings.Finished.title))
])

init() {
Expand All @@ -28,17 +28,3 @@ final class FinishedScreenView: UIView {

required init?(coder: NSCoder) { nil }
}

// MARK: - FormItem.Configuration

private extension FormTextItem.Configuration {
static let title = FormTextItem.Configuration(
text: "Horray! You finished the onboarding. 🎉",
attributes: [
.font: UIFont(name: "AvenirNext-DemiBold", size: 30)!,
.foregroundColor: UIColor.label,
.kern: 0.5,
],
spacingAfter: 20
)
}
Loading

0 comments on commit f96d0f9

Please sign in to comment.