Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IOS-9604 Added infinite interval to crouton and snackbar for the Swif… #324

Merged
merged 6 commits into from
Dec 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ class UICatalogCroutonViewController: UITableViewController {

private lazy var croutonDismissIntervalCell: UISegmentedControlTableViewCell = {
let cell = UISegmentedControlTableViewCell(reuseIdentifier: "crouton-dismiss-interval")
for interval in CroutonDismissInterval.allCases {
for interval in SnackbarCatalogDismissInterval.allCases {
cell.segmentedControl.insertSegment(withTitle: "\(timeIntervalDescription(from: interval)) seconds", at: 0, animated: false)
}
cell.segmentedControl.selectedSegmentIndex = 0
Expand Down Expand Up @@ -116,11 +116,16 @@ extension UICatalogCroutonViewController {
view.endEditing(true)

if indexPath.row == 2 {
let config = SnackbarConfig(
title: titleCell.textField.text ?? "",
dismissInterval: croutonDismissInterval
)
CroutonController.shared.showCrouton(
withText: titleCell.textField.text ?? "",
action: croutonAction,
config: config,
style: selectedCroutonStyle,
croutonDismissInterval: croutonDismissInterval,
dismissHandler: { reason in
print("\(reason.rawValue)")
},
forceDismiss: forceDismiss
)
} else {
Expand All @@ -145,9 +150,33 @@ private extension UICatalogCroutonViewController {
return CroutonController.ActionConfig(text: title, handler: { print("Crouton Action Tapped") })
}

var croutonDismissInterval: CroutonDismissInterval? {
var croutonDismissInterval: SnackbarDismissInterval {
let selectedCroutonDismissIntervalIndex = croutonDismissIntervalCell.segmentedControl.selectedSegmentIndex
return CroutonDismissInterval(rawValue: selectedCroutonDismissIntervalIndex)
let catalogDismissInterval = SnackbarCatalogDismissInterval(rawValue: selectedCroutonDismissIntervalIndex)

switch catalogDismissInterval {
case .fiveSeconds:
return .fiveSeconds
case .tenSeconds:
guard let actionTitle = actionTitleCell.textField.text, !actionTitle.isEmpty else {
return .tenSeconds(SnackbarAction(title: "Action", handler: {}))
}

return .tenSeconds(SnackbarAction(title: actionTitle, handler: {}))

case .infinite:
guard let action = actionTitleCell.textField.text, !action.isEmpty else {
return .infiniteWithClose(nil)
}

guard forceDismiss else {
return .infinite(SnackbarAction(title: action, handler: {}))
}

return .infiniteWithClose(SnackbarAction(title: action, handler: {}))
case .none:
return .fiveSeconds
}
}

var forceDismiss: Bool {
Expand Down Expand Up @@ -176,7 +205,7 @@ private extension Section {
}
}

public extension CroutonDismissInterval {
extension SnackbarCatalogDismissInterval {
init?(rawValue: Int) {
switch rawValue {
case 0:
Expand Down Expand Up @@ -218,17 +247,21 @@ private class SampleTabBarViewController: UITabBarController {

override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)

var config: SnackbarConfig
if let action = action {
config = SnackbarConfig(title: text, dismissInterval: .tenSeconds(SnackbarAction(title: action.text, handler: action.handler)))
} else {
config = SnackbarConfig(title: text, dismissInterval: .fiveSeconds)
}
CroutonController.shared.showCrouton(
withText: text,
action: action,
config: config,
style: style
)
}
}

private extension UICatalogCroutonViewController {
func timeIntervalDescription(from interval: CroutonDismissInterval) -> String {
func timeIntervalDescription(from interval: SnackbarCatalogDismissInterval) -> String {
switch interval {
case .fiveSeconds:
return "5"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ extension UICatalogEmptyStateViewController: UITableViewDataSource, UITableViewD

let actions: EmptyStateConfiguration.EmptyStateActions
let handler: () -> Void = {
CroutonController.shared.showCrouton(withText: "The user has tapped any button")
CroutonController.shared.showCrouton(config: SnackbarConfig(title: "The user has tapped any button", dismissInterval: .fiveSeconds))
}
switch buttonsCell.segmentedControl.selectedSegmentIndex {
case 0:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,24 @@
import MisticaSwiftUI
import SwiftUI

enum SnackbarCatalogDismissInterval: CaseIterable {
case fiveSeconds
case tenSeconds
case infinite
}

struct SnackbarCatalogView: View {
@State var title: String = "Message"
@State var buttonTitle: String = "Action"
@State var selectedStyleIndex = 0
@State var styles: [SnackbarStyle] = [.normal, .error]
@State var selectedButtonStyleIndex = 0
@State var buttonStyles: [SnackbarButtonStyle] = [.short, .large]
@State var presentingSnackbar = false
@State var presentingCrouton = false
@State var autoDismissDelay = 3
@State var selectedIntervalStyleIndex = 0
@State var hasForceDismissAction: Bool = false
private let styles: [SnackbarStyle] = [.normal, .error]
private let buttonStyles: [SnackbarButtonStyle] = [.short, .large]
private let intervalStyles: [SnackbarCatalogDismissInterval] = SnackbarCatalogDismissInterval.allCases

var body: some View {
List {
Expand All @@ -29,16 +37,21 @@ struct SnackbarCatalogView: View {
)
.endEditingOnTap()
}
section("Button") {
TextField(
"Button Title",
text: $buttonTitle
)
.endEditingOnTap()
if intervalStyles[selectedIntervalStyleIndex] != .fiveSeconds {
section("Button") {
TextField(
"Button Title",
text: $buttonTitle
)
.endEditingOnTap()
}
}
section("Style") { stylePicker }
section("Auto Dismiss Delay") { Stepper("\(autoDismissDelay) seconds", value: $autoDismissDelay) }
section("Auto Dismiss Delay") { intervalPicker }
section("Button Style") { buttonStylePicker }
if intervalStyles[selectedIntervalStyleIndex] == .infinite && !buttonTitle.isEmpty {
section("Force Dismiss") { Toggle("Has force dismiss action", isOn: $hasForceDismissAction) }
}
section("Snackbar") {
Button("Show snackbar") {
withAnimation {
Expand All @@ -60,22 +73,47 @@ struct SnackbarCatalogView: View {
isVisible: $presentingSnackbar,
style: styles[selectedStyleIndex],
buttonStyle: buttonStyles[selectedButtonStyleIndex],
autoDismissDelay: TimeInterval(autoDismissDelay),
title: title,
buttonTitle: buttonTitle,
buttonAction: {}
config: SnackbarConfig(
title: title,
dismissInterval: dismissInterval
),
dismissHandlerBlock: { reason in
print(reason.rawValue)
}
)
.crouton(
isVisible: $presentingCrouton,
style: styles[selectedStyleIndex],
buttonStyle: buttonStyles[selectedButtonStyleIndex],
autoDismissDelay: TimeInterval(autoDismissDelay),
title: title,
buttonTitle: buttonTitle,
buttonAction: {}
config: SnackbarConfig(
title: title,
dismissInterval: dismissInterval
),
dismissHandlerBlock: { reason in
print(reason.rawValue)
}
)
}

var dismissInterval: SnackbarDismissInterval {
switch intervalStyles[selectedIntervalStyleIndex] {
case .fiveSeconds:
return .fiveSeconds
case .tenSeconds:
return .tenSeconds(SnackbarAction(title: buttonTitle.isEmpty ? "Action" : buttonTitle, handler: {}))
case .infinite:
if !buttonTitle.isEmpty {
if hasForceDismissAction {
return .infiniteWithClose(SnackbarAction(title: buttonTitle, handler: {}))
} else {
return .infinite(SnackbarAction(title: buttonTitle, handler: {}))
}
} else {
return .infiniteWithClose(nil)
}
}
}

@ViewBuilder
var stylePicker: some View {
picker($selectedStyleIndex, options: styles)
Expand All @@ -85,6 +123,26 @@ struct SnackbarCatalogView: View {
var buttonStylePicker: some View {
picker($selectedButtonStyleIndex, options: buttonStyles)
}

@ViewBuilder
var intervalPicker: some View {
picker($selectedIntervalStyleIndex, options: intervalStyles)
}
}

extension SnackbarCatalogView {
func timeIntervalDescription(from interval: SnackbarDismissInterval) -> String {
switch interval {
case .fiveSeconds:
return "5"
case .tenSeconds:
return "10"
case .infinite:
return "∞"
case .infiniteWithClose:
return "∞ close"
}
}
}

// MARK: CustomStringConvertible
Expand All @@ -111,6 +169,19 @@ extension SnackbarButtonStyle: CustomStringConvertible {
}
}

extension SnackbarCatalogDismissInterval: CustomStringConvertible {
public var description: String {
switch self {
case .fiveSeconds:
return "Five Seconds"
case .tenSeconds:
return "Ten Seconds"
case .infinite:
return "Infinite"
}
}
}

// MARK: Previews

#if DEBUG
Expand Down
23 changes: 2 additions & 21 deletions Sources/Mistica/Components/Crouton/Domain/CroutonConfig.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,32 +14,13 @@ import UIKit
case critical
}

public enum CroutonDismissInterval: CaseIterable {
case fiveSeconds
case tenSeconds
case infinite
}

public extension CroutonDismissInterval {
var timeInterval: TimeInterval? {
switch self {
case .fiveSeconds:
return 5
case .tenSeconds:
return 10
case .infinite:
return nil
}
}
}

public struct CroutonConfig {
let backgroundColor: UIColor
let textColor: UIColor
let actionStyle: Button.Style
let overrideDismissInterval: CroutonDismissInterval
let overrideDismissInterval: SnackbarDismissInterval

public init(style: CroutonStyle, croutonDismissInterval: CroutonDismissInterval) {
public init(style: CroutonStyle, croutonDismissInterval: SnackbarDismissInterval) {
switch style {
case .info:
backgroundColor = .feedbackInfoBackground
Expand Down
Loading