Skip to content

Commit

Permalink
Merge pull request #37 from payan-app/snackbar
Browse files Browse the repository at this point in the history
Add fixes to snackbar
  • Loading branch information
juandahurt authored Dec 15, 2022
2 parents ba37278 + d9c25d2 commit d7efbf4
Show file tree
Hide file tree
Showing 9 changed files with 420 additions and 6 deletions.
47 changes: 41 additions & 6 deletions PuraceDemo/PuraceDemo/Examples/Basic/SnackbarExample.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,51 @@ import SwiftUI
import Purace

struct SnackBarExample: View {
@State var showSnackbar = false
@State var showActionButton = false
private let types = ["info", "error", "alert"]
@State var selectedType = "info"

func getType() -> PuraceSnackbarType {
switch selectedType {
case "info":
return .info
case "error":
return .error
case "alert":
return .alert
default: return .error
}
}

var body: some View {
VStack {
Text("`PuraceSnackbarView(title: ...)`")
.padding()
PuraceButtonView(!showSnackbar ? "Mostrar snackbar" : "Ocultar snackbar", fontSize: 14) {
showSnackbar = !showSnackbar
HStack {
Toggle(isOn: $showActionButton) {
PuraceTextView("Mostrar el botón de acción")
}
}

HStack {
PuraceTextView("Tipo")
Picker("", selection: $selectedType) {
ForEach(types, id: \.self) {
Text($0)
}
}
Spacer()
}

PuraceButtonView("Mostrar snackbar", fontSize: 14) {
PuraceSnackbarBuilder()
.withTitle("Hubo un error")
.withType(getType())
.withAction(title: showActionButton ? "REINTENTAR" : nil, handler: {
print("Action button tapped")
})
.build()
.show()
}
Spacer()
}.snackBar(title: "Parece que ha ocurrido un error", isVisible: $showSnackbar, type: .info, buttonTitle: "REINTENTAR", duration: .long, dismissOnDrag: true)
}.padding(.horizontal)
}
}
18 changes: 18 additions & 0 deletions Sources/Purace/Common/Extensions/UIApplication+keyWindow.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//
// UIApplication+keyWindow.swift
//
//
// Created by Juan Hurtado on 21/11/22.
//

import UIKit

extension UIApplication {
var keyWindow: UIWindow? {
return UIApplication.shared.connectedScenes
.filter { $0.activationState == .foregroundActive }
.first(where: { $0 is UIWindowScene })
.flatMap({ $0 as? UIWindowScene })?.windows
.first(where: \.isKeyWindow)
}
}
34 changes: 34 additions & 0 deletions Sources/Purace/Common/Extensions/UIView+NibLoadable.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//
// File.swift
//
//
// Created by Juan Hurtado on 19/11/22.
//

import Foundation
import UIKit

public protocol NibLoadable {
static var nibName: String { get }
}

public extension NibLoadable where Self: UIView {
static var nibName: String {
return String(describing: Self.self)
}

static var nib: UINib {
let bundle = Bundle.module
return UINib(nibName: Self.nibName, bundle: bundle)
}

func setupFromNib() {
guard let view = Self.nib.instantiate(withOwner: self, options: nil).first as? UIView else { fatalError("Error loading \(self) from nib") }
addSubview(view)
view.translatesAutoresizingMaskIntoConstraints = false
view.leadingAnchor.constraint(equalTo: self.safeAreaLayoutGuide.leadingAnchor, constant: 0).isActive = true
view.topAnchor.constraint(equalTo: self.safeAreaLayoutGuide.topAnchor, constant: 0).isActive = true
view.trailingAnchor.constraint(equalTo: self.safeAreaLayoutGuide.trailingAnchor, constant: 0).isActive = true
view.bottomAnchor.constraint(equalTo: self.safeAreaLayoutGuide.bottomAnchor, constant: 0).isActive = true
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
//
// PuraceSnackbar.swift
//
//
// Created by Juan Hurtado on 19/11/22.
//

import UIKit

// TODO: update name to `PuraceSnackbarView`
class PuraceSnackbar: UIView, NibLoadable {
@IBOutlet var contentView: UIView!
@IBOutlet private weak var actionButton: UIButton!
@IBOutlet private weak var titleLabel: UILabel!

private var actionHandler: (() -> Void)?

override init(frame: CGRect) {
super.init(frame: frame)
setupFromNib()
translatesAutoresizingMaskIntoConstraints = false
setupSubviews()
}

required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

private func setupSubviews() {
titleLabel.font = UIFont(name: "Poppins-Regular", size: 14)
titleLabel.textColor = .white

actionButton.titleLabel?.textColor = .white
actionButton.titleLabel?.font = UIFont(name: "Poppins-Medium", size: 14)

contentView.layer.cornerRadius = 10
}

func setTitle(_ title: String) {
titleLabel.text = title
}

func setType(_ type: PuraceSnackbarType) {
switch type {
case .info:
contentView.backgroundColor = .init(PuraceStyle.Color.G1)
case .alert:
contentView.backgroundColor = .init(PuraceStyle.Color.B1)
case .error:
contentView.backgroundColor = .init(PuraceStyle.Color.R1)
}
}

func setAction(withTitle title: String?, _ handler: (() -> Void)?) {
actionButton.setTitle(title, for: .normal)
if title != nil {
actionHandler = handler
}
}

@IBAction private func onActionButtonTap(_ sender: UIButton) {
actionHandler?()
}
}

// MARK: - Config constants
extension PuraceSnackbar {
static let height: CGFloat = 60
static let padding: CGFloat = 20
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21507" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_12" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21505"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="PuraceSnackbar" customModuleProvider="target">
<connections>
<outlet property="actionButton" destination="nek-Ra-1ia" id="c3m-MM-Pc2"/>
<outlet property="contentView" destination="fTQ-8B-eqd" id="d4d-wB-YV5"/>
<outlet property="titleLabel" destination="Vd3-Fo-KXQ" id="56M-lz-Bvd"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="fTQ-8B-eqd">
<rect key="frame" x="0.0" y="0.0" width="393" height="134"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" spacing="20" translatesAutoresizingMaskIntoConstraints="NO" id="KDH-Pp-IBp">
<rect key="frame" x="16" y="10" width="361" height="114"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Vd3-Fo-KXQ">
<rect key="frame" x="0.0" y="0.0" width="287" height="114"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<button opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" contentHorizontalAlignment="trailing" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="nek-Ra-1ia">
<rect key="frame" x="307" y="0.0" width="54" height="114"/>
<constraints>
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="54" id="8po-gU-5S4"/>
</constraints>
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
<state key="normal" title="Button"/>
<connections>
<action selector="onActionButtonTap:" destination="-1" eventType="touchUpInside" id="Q4Y-Oo-hvy"/>
</connections>
</button>
</subviews>
</stackView>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="bottom" secondItem="KDH-Pp-IBp" secondAttribute="bottom" constant="10" id="KTd-2R-oPA"/>
<constraint firstItem="KDH-Pp-IBp" firstAttribute="top" secondItem="fTQ-8B-eqd" secondAttribute="top" constant="10" id="VWq-WI-MU4"/>
<constraint firstItem="KDH-Pp-IBp" firstAttribute="leading" secondItem="fTQ-8B-eqd" secondAttribute="leading" constant="16" id="bpp-hc-zHa"/>
<constraint firstAttribute="trailing" secondItem="KDH-Pp-IBp" secondAttribute="trailing" constant="16" id="fHb-YZ-v7m"/>
</constraints>
<nil key="simulatedTopBarMetrics"/>
<nil key="simulatedBottomBarMetrics"/>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<point key="canvasLocation" x="319.84732824427482" y="292.25352112676057"/>
</view>
</objects>
</document>
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//
// PuraceSnackbarContent.swift
//
//
// Created by Juan Hurtado on 21/11/22.
//

import Foundation

public struct PuraceSnackbarContent {
var title: String = ""
var type: PuraceSnackbarType = .info
var action: (() -> Void)?
var actionTitle: String?
}
47 changes: 47 additions & 0 deletions Sources/Purace/Views/Basic/Snackbar v2/PuraceSnackbarBuilder.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
//
// PuraceSnackbarBuilder.swift
//
//
// Created by Juan Hurtado on 14/12/22.
//

import Foundation

/// Snackbar builder.
///
/// If you want to build and show a snackbar:
/// ```
/// let builder = PuraceSnackbarBuilder()
///
/// builder
/// .withTitle("This is a snackbar!")
/// .build()
/// .show()
/// ```
public class PuraceSnackbarBuilder {
private var content: PuraceSnackbarContent

public init() {
content = PuraceSnackbarContent()
}

public func withTitle(_ title: String) -> PuraceSnackbarBuilder {
content.title = title
return self
}

public func withType(_ type: PuraceSnackbarType) -> PuraceSnackbarBuilder {
content.type = type
return self
}

public func withAction(title: String?, handler: @escaping () -> Void) -> PuraceSnackbarBuilder {
content.actionTitle = title
content.action = handler
return self
}

public func build() -> PuraceSnackbarDisplayableContent {
PuraceSnackbarDisplayableContent(content: content)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//
// PuraceSnackbarDisplayableContent.swift
//
//
// Created by Juan Hurtado on 14/12/22.
//

import Foundation

public class PuraceSnackbarDisplayableContent {
private let content: PuraceSnackbarContent

init(content: PuraceSnackbarContent) {
self.content = content
}

public func show() {
PuraceSnackbarManager.instance.show(using: content)
}
}
Loading

0 comments on commit d7efbf4

Please sign in to comment.