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

Feat UIKit Hint #273

Merged
merged 213 commits into from
Oct 22, 2024
Merged
Show file tree
Hide file tree
Changes from 211 commits
Commits
Show all changes
213 commits
Select commit Hold shift + click to select a range
38280a7
Add Tooltip view
kevinneko Jan 30, 2024
6bff03f
Refactor Tooltip style
kevinneko Jan 30, 2024
7caa72c
Merge branch 'main' into feat-swiftui-tooltip
kevinneko Jan 31, 2024
c5e0daa
Can adjust tooltip position
kevinneko Jan 31, 2024
cbd58af
Add tooltip playground for testing
kevinneko Jan 31, 2024
7d13811
Refine layout tips logic
kevinneko Jan 31, 2024
874a5b9
Refine layout logic
kevinneko Jan 31, 2024
eecaff8
Update CharcoalTooltip.swift
kevinneko Jan 31, 2024
0ea9f6a
Refine tooltip spacing
kevinneko Feb 6, 2024
085626f
Add CharcoalIdentifiableOverlayView
kevinneko Feb 6, 2024
b12beac
Use Actor to prevent Data Race
kevinneko Feb 6, 2024
d2c39e5
Remove CharcoalIdentifiableOverlayView out
kevinneko Feb 6, 2024
83cb45f
Clean code
kevinneko Feb 6, 2024
1a5cd1b
Only update view when it is isPresenting
kevinneko Feb 6, 2024
747da2a
Clean access control
kevinneko Feb 6, 2024
61fd850
Add TooltipsView
kevinneko Feb 6, 2024
7883c8a
Fix tooltipY layout logic
kevinneko Feb 6, 2024
a0cbea0
Use main actor and remove CharcoalContainerManagerKey
kevinneko Feb 6, 2024
bbb6b90
Fix access control on CharcoalContainerManager
kevinneko Feb 6, 2024
f5b77b3
Make viewID as @State
kevinneko Feb 6, 2024
5020edf
Use EnviromentObject to create CharcoalContainerManager for each cont…
kevinneko Feb 8, 2024
793a635
Use ObservedObject on CharcoalContainerManager
kevinneko Feb 8, 2024
131c2dd
Add use charcoal button as demo trigger
kevinneko Feb 12, 2024
3b4e47b
Add arrow logic on tooltip
kevinneko Feb 12, 2024
d902eed
Refine arrow logic
kevinneko Feb 12, 2024
9ae7e05
Refine arrow layout logic
kevinneko Feb 12, 2024
968feb9
Use StateObject to prevent unexpected reinit
kevinneko Feb 12, 2024
1539dac
Refactor TooltipBubbleShape
kevinneko Feb 12, 2024
ca43fec
Fix edge layout logic
kevinneko Feb 12, 2024
506345d
Add comment
kevinneko Feb 12, 2024
08b32dd
Format code
kevinneko Feb 12, 2024
2de961e
Use new approach to remove adaptiveMaxWidth
kevinneko Feb 12, 2024
64586f5
Fix the tip bubble's position latency
kevinneko Feb 12, 2024
abdd345
Add dismiss when interaction
kevinneko Feb 20, 2024
e38ca0e
Reformat
kevinneko Feb 20, 2024
720bb56
Add initial Snackbar
kevinneko Feb 20, 2024
bf66953
Add thumbnail image
kevinneko Feb 21, 2024
238768c
Add support for thumbnailImage and action
kevinneko Feb 21, 2024
7aa797f
Clean code
kevinneko Feb 21, 2024
79d6caa
Reformat code
kevinneko Feb 21, 2024
ac539d6
Rename ActionContent
kevinneko Feb 21, 2024
c593130
Replace thumbnailImage type
kevinneko Feb 21, 2024
701198d
Add dismissOnTouchOutside control
kevinneko Feb 21, 2024
6db7a74
Add comment on CharcoalIdentifiableOverlayView
kevinneko Feb 21, 2024
63da0c1
Update CharcoalTooltip.swift
kevinneko Feb 21, 2024
b58fb42
Add SnackBar demo
kevinneko Feb 21, 2024
75c92ee
Replace thumbnail with charcoal logo
kevinneko Feb 21, 2024
0bf8e8e
Use @ViewBuilder
kevinneko Feb 21, 2024
5e534bb
Clean Code
kevinneko Feb 21, 2024
d9fbca4
Made code more readable
kevinneko Feb 21, 2024
bd664eb
Update ToastsView.swift
kevinneko Feb 21, 2024
0ead7e9
Add auto dismiss logic
kevinneko Feb 27, 2024
e1ee7c2
Fix dismiss comment
kevinneko Feb 27, 2024
388452d
Add Identifiable to CharcoalIdentifiableOverlayView
kevinneko Feb 27, 2024
7a84acf
Make all CharcoalPopupView identifiable
kevinneko Feb 27, 2024
e9744a8
Move all control logic into CharcoalPopupView
kevinneko Feb 27, 2024
0b09383
Reformat
kevinneko Feb 27, 2024
92bcc5a
Refine CharcoalOverlayContainerChild logic of updating view
kevinneko Feb 27, 2024
53e02b6
Rename to CharcoalOverlayUpdaterContainer
kevinneko Feb 27, 2024
e10a885
Add CharcoalToast
kevinneko Feb 27, 2024
c39ad76
Refine toast control
kevinneko Feb 27, 2024
fce7270
Refine screen edge of toast
kevinneko Feb 27, 2024
bdba4d3
Refine comments
kevinneko Feb 27, 2024
70417ba
Rename CharcoalPopupProtocol
kevinneko Feb 27, 2024
87a129c
Refine isActuallyPresenting logic
kevinneko Feb 27, 2024
6cf98c9
Clean animation
kevinneko Feb 27, 2024
c16d318
Add animation configuration
kevinneko Feb 27, 2024
edc2ea6
Add custom animation
kevinneko Feb 27, 2024
c939bc9
Add CharcoalToastProtocol
kevinneko Feb 28, 2024
b2ca18d
Makes CharcoalSnackBar adapt CharcoalToastProtocol
kevinneko Feb 28, 2024
d829f8f
Remove time delay
kevinneko Feb 28, 2024
db5466f
Refine SnackBar Animation logic
kevinneko Feb 28, 2024
5b39c79
Add CharcoalToastAnimationModifier
kevinneko Feb 28, 2024
a0e0992
Reformat code
kevinneko Feb 28, 2024
8412cd0
Update CharcoalPopupViewEdge of direction
kevinneko Feb 28, 2024
932ffae
Refine demo
kevinneko Feb 28, 2024
333503b
Fix missing animation
kevinneko Feb 28, 2024
fe42a48
Rename charcoalAnimatedToast to charcoalAnimatableToast
kevinneko Feb 28, 2024
ffeec3f
Rename CharcoalAnimatableToastProtocol
kevinneko Feb 28, 2024
be2a909
Rename for clean
kevinneko Feb 28, 2024
0093126
Simplify protocols
kevinneko Feb 28, 2024
18f4ade
Add drag control
kevinneko Mar 5, 2024
3d1b63c
Add Dismiss timer control logic
kevinneko Mar 5, 2024
48485f2
Refine drag damping logic
kevinneko Mar 5, 2024
023bfd9
Add CharcoalToastDraggable
kevinneko Mar 6, 2024
e3b8f46
Use CharcoalToastDraggableModifier on CharcoalSnackBar
kevinneko Mar 6, 2024
82b5c89
Format code
kevinneko Mar 6, 2024
44c462f
Add init structure
kevinneko Mar 12, 2024
8bbe79e
Add action button
kevinneko Mar 12, 2024
4fb12f7
Replace placeholder with ja text
kevinneko Mar 12, 2024
17e9376
Use CGPath union for iOS 16
kevinneko Mar 12, 2024
d145b7e
Update TooltipBubbleShape.swift
kevinneko Mar 12, 2024
0e475bc
Update CharcoalTooltip.swift
kevinneko Mar 12, 2024
cd032e0
Use GeometryReader on overlay
kevinneko Mar 12, 2024
a2b5f14
Use new path draw logic
kevinneko Mar 12, 2024
9851ca6
Refine arrow width
kevinneko Mar 12, 2024
5cc7b99
Refine arrow width
kevinneko Mar 13, 2024
3835ba9
Clean Code
kevinneko Mar 13, 2024
14f61fc
Refine preview
kevinneko Mar 13, 2024
ca5e9ca
Use timer instead of DispatchQueue
kevinneko Mar 13, 2024
597faf3
Refine layout logic
kevinneko Mar 13, 2024
996ea88
Refine arrow logic
kevinneko Mar 13, 2024
bb8cc96
Refine layout logic
kevinneko Mar 26, 2024
12bc105
Add missing charcoalOverlayContainer
kevinneko Mar 26, 2024
8e07941
Add Balloon to examples
kevinneko Mar 26, 2024
47eeb08
Add default tutorials
kevinneko Mar 26, 2024
a4060aa
Remove overlay when disappear
kevinneko Mar 26, 2024
42c85e2
Refine charcoalOverlayContainer place
kevinneko Mar 26, 2024
77d0aa6
Refine
kevinneko Mar 26, 2024
f708b1e
Update CharcoalSnackBar.swift
kevinneko Mar 26, 2024
9611aab
Add Charcoal Hint
kevinneko Mar 27, 2024
75e7b02
Use surface 3
kevinneko Mar 27, 2024
d4b5e24
Add isPresenting
kevinneko Mar 27, 2024
f911e75
Add hints to sample
kevinneko Mar 27, 2024
1b5c179
Format code
kevinneko Mar 27, 2024
4e67667
Init CharcoalTooltipView
kevinneko Apr 24, 2024
225c31e
Init Bubble shape
kevinneko Apr 24, 2024
51eff4a
Refine tooltip preview
kevinneko Apr 24, 2024
b658ce2
Rename as Charcoal Bubble Shape
kevinneko Apr 30, 2024
0073b9e
Add Label to tooltip
kevinneko Apr 30, 2024
15ffb14
Update text frame when traitCollection did change
kevinneko Apr 30, 2024
567de17
Update CharcoalTooltipView.swift
kevinneko Apr 30, 2024
6b1ae10
Add CharcoalTooltip
kevinneko Apr 30, 2024
ef1684c
Can debug show on method
kevinneko Apr 30, 2024
c7e60ae
Can layout point
kevinneko Apr 30, 2024
972e3b2
Can redraw target point
kevinneko Apr 30, 2024
1d0fb67
Update CharcoalTooltip.swift
kevinneko Apr 30, 2024
6f73f32
Refine tooltip display
kevinneko May 1, 2024
3efb6f3
Share the logic
kevinneko May 1, 2024
87ce7c2
Use interaction mode
kevinneko May 1, 2024
e0ba65e
Use CharcoalOverlayContainerView
kevinneko May 1, 2024
71bb979
Update CharcoalOverlay.swift
kevinneko May 1, 2024
8c5bf82
Refactor to ChacoalOverlayManager
kevinneko May 1, 2024
b391488
Makes CharcoalIdentifiableOverlayView Identifiable
kevinneko May 1, 2024
9586ce4
Refine layout logic
kevinneko May 1, 2024
a417758
Add display(view: CharcoalIdentifiableOverlayView)
kevinneko May 1, 2024
37cee23
Add tooltip to uikit example
kevinneko May 1, 2024
3c62e22
Update Tooltips.swift
kevinneko May 1, 2024
df2f52a
Add CharcoalIdentifiableOverlayDelegate
kevinneko May 1, 2024
ff1d909
Reformat
kevinneko May 1, 2024
dfe1553
Update StringExtension.swift
kevinneko May 1, 2024
a71477b
Add to UIKitSample
kevinneko May 1, 2024
479eaef
Merge branch 'main' into feat-swiftui-tooltip
kevinneko May 8, 2024
11c805a
Fix public requirements
kevinneko May 8, 2024
658afd5
Merge branch 'feat-swiftui-tooltip' into feat-uikit-tooltip
kevinneko May 8, 2024
6d1c039
Reformat
kevinneko May 8, 2024
9dcdb2c
Use touch began to handle dismiss on touch
kevinneko May 8, 2024
7708f10
Update CharcoalIdentifiableOverlayView.swift
kevinneko May 8, 2024
f033646
Merge branch 'feat-swiftui-tooltip' into feat-swiftui-toast
kevinneko May 8, 2024
d9acdfb
Merge branch 'feat-uikit-tooltip' into feat-uikit-toast
kevinneko May 14, 2024
67a9672
Add CharcoalToastView
kevinneko May 14, 2024
03b5735
change cornerRadius
kevinneko May 14, 2024
4ccd046
Add CharcoalToast
kevinneko May 15, 2024
752ba6d
Move show logic out
kevinneko May 15, 2024
1f10419
Reformat
kevinneko May 15, 2024
e0231f0
Refine dismiss method
kevinneko May 15, 2024
144e132
Merge branch 'feat-uikit-tooltip' into feat-uikit-toast
kevinneko May 15, 2024
a8cde5d
Update CharcoalToast.swift
kevinneko May 15, 2024
f75fb7a
Add ActionContent and ActionComplete callback
kevinneko May 15, 2024
818db64
Merge branch 'feat-uikit-tooltip' into feat-uikit-toast
kevinneko May 15, 2024
6b6bd1a
Update CharcoalToast.swift
kevinneko May 15, 2024
0f18ca5
Update CharcoalBubbleShape_UIKit.swift
kevinneko May 15, 2024
c9f9d4f
Merge branch 'feat-uikit-tooltip' into feat-uikit-toast
kevinneko May 15, 2024
fd50bc3
Refine layout animation logic
kevinneko May 15, 2024
e203f76
Refine animation
kevinneko May 15, 2024
0ebb974
Add dismiss
kevinneko May 15, 2024
56d9243
Add example
kevinneko May 15, 2024
72f12b0
Reformat
kevinneko May 15, 2024
eb25b09
Add toasts example
kevinneko May 15, 2024
d6a4577
Add CharcoalSnackBarView
kevinneko May 28, 2024
beed8a7
Update project.pbxproj
kevinneko May 28, 2024
ef5f9d7
Clean code
kevinneko May 28, 2024
23b6c01
Refine layout logic
kevinneko May 28, 2024
95ccac0
Add CharcoalSnackBar
kevinneko May 28, 2024
90fbeb5
Update CharcoalSnackBar.swift
kevinneko May 28, 2024
639a46e
Update CharcoalSnackBar.swift
kevinneko May 28, 2024
7a06da4
Refine layout logic
kevinneko May 28, 2024
9ff4f22
Refine toasts text
kevinneko May 28, 2024
b5256e1
Update CharcoalToastDraggableModifier.swift
kevinneko May 28, 2024
eb59f4f
Add CharcoalRubberGesture
kevinneko May 29, 2024
5773c8d
use id to notify did dismiss
kevinneko May 29, 2024
e14e161
Add rubber gesture
kevinneko May 29, 2024
ac6f35c
Refactor
kevinneko May 29, 2024
9b03460
Refactor
kevinneko May 29, 2024
5355834
Fix memory leak
kevinneko May 29, 2024
6167fb7
Format
kevinneko May 29, 2024
85dba89
Fix memory leak
kevinneko May 29, 2024
d153e95
Add example
kevinneko May 29, 2024
2c346f3
Refine snackbar
kevinneko May 29, 2024
dde2404
Merge branch 'main' into feat-swiftui-tooltip
kevinneko May 30, 2024
a2e52b9
Merge branch 'main' into feat-swiftui-tooltip
kevinneko May 30, 2024
e55d4f0
Merge branch 'feat-swiftui-tooltip' into feat-uikit-tooltip
kevinneko May 30, 2024
c185ec5
Merge branch 'feat-uikit-tooltip' into feat-swiftui-toast
kevinneko May 31, 2024
3a1cb2b
Merge branch 'feat-swiftui-toast' into feat-uikit-toast
kevinneko May 31, 2024
33ec9d0
Merge branch 'feat-uikit-toast' into feat-swiftui-hint
kevinneko May 31, 2024
db2b048
Update project.pbxproj
kevinneko May 31, 2024
44e5c29
Add CharcoalHintView
kevinneko May 31, 2024
1bd76dc
Update HintView.swift
kevinneko May 31, 2024
2981598
Update HintView.swift
kevinneko May 31, 2024
b210e63
Add example
kevinneko May 31, 2024
fb2cb70
Refine swift lint
kevinneko May 31, 2024
a573a8b
Refactor CharcoalToastView
kevinneko May 31, 2024
4bf3208
Refactor CharcoalSnackBarView
kevinneko May 31, 2024
397ebec
Reformat
kevinneko May 31, 2024
2c5dd37
Refine self logic
kevinneko May 31, 2024
6333a45
Merge branch 'feat-uikit-toast' into feat-swiftui-hint
kevinneko Jun 4, 2024
2b49d78
Merge branch 'feat-swiftui-hint' into feat-uikit-hint
kevinneko Jun 4, 2024
b85cc3f
Squashed commit of the following:
kevinneko Oct 9, 2024
28894c2
Delete スクリーンショット 2024-02-21 17.28.10.png
kevinneko Oct 9, 2024
3d71d43
Merge branch 'main' into feat-uikit-hint
kevinneko Oct 15, 2024
d8f506d
Fixed icon and refine spacing
kevinneko Oct 22, 2024
32c681f
Clean files
kevinneko Oct 22, 2024
6025837
Use shared CharcoalAction
kevinneko Oct 22, 2024
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 @@ -52,6 +52,7 @@ public final class ContentViewController: UIViewController {
case tooltips = "Tooltips"
case toasts = "Toasts"
case spinners = "Spinners"
case hints = "Hints"
case balloons = "Balloons"

var viewController: UIViewController {
Expand All @@ -74,6 +75,8 @@ public final class ContentViewController: UIViewController {
return ToastsViewController()
case .spinners:
return SpinnersViewController()
case .hints:
return HintsViewController()
case .balloons:
return BalloonsViewController()
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import Charcoal
import UIKit

final class HintsViewController: UIViewController {
private lazy var scrollView: UIScrollView = {
let view = UIScrollView(frame: .zero)
view.bounces = true
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()

private lazy var stackView: UIStackView = {
let view = UIStackView(frame: .zero)
view.axis = .vertical
view.spacing = 16
view.alignment = .center
view.distribution = .equalSpacing
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()

let cellReuseIdentifier = "cell"

private var hints: [CharcoalHintView] = [
CharcoalHintView(text: "Hello World"),
CharcoalHintView(text: "ブックマークしました"),
CharcoalHintView(text: "ブックマークしました", action: CharcoalAction(title: "Button", actionCallback: {
print("Button taped")
})),
CharcoalHintView(
text: "こんにちは",
action: CharcoalAction(title: "Button", actionCallback: {
print("Button taped")
})
)
]

private var switchingButton: CharcoalSwitchingButton!

override func viewDidLoad() {
super.viewDidLoad()
setupUI()
addHintViews()
}

private func setupUI() {
view.backgroundColor = UIColor.systemBackground

view.addSubview(scrollView)

NSLayoutConstraint.activate([
scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
scrollView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor)
])

scrollView.addSubview(stackView)

NSLayoutConstraint.activate([
stackView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16),
stackView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -16),
stackView.topAnchor.constraint(equalTo: scrollView.topAnchor),
stackView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor)
])
}

private func addHintViews() {
for example in hints {
let hint = example
hint.translatesAutoresizingMaskIntoConstraints = false
stackView.addArrangedSubview(hint)
hint.widthAnchor.constraint(equalTo: stackView.widthAnchor).isActive = true
}
}

}

@available(iOS 17.0, *)
#Preview {
let viewController = HintsViewController()
return viewController
}
7 changes: 7 additions & 0 deletions Sources/CharcoalShared/Extensions/CGSize+Extension.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import Foundation

public extension CGSize {
kevinneko marked this conversation as resolved.
Show resolved Hide resolved
var area: CGFloat {
return width * height
}
}
11 changes: 11 additions & 0 deletions Sources/CharcoalShared/Extensions/UIColor+Extension.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import UIKit

public extension UIColor {
kevinneko marked this conversation as resolved.
Show resolved Hide resolved
func imageWithColor(width: Int, height: Int) -> UIImage {
let size = CGSize(width: width, height: height)
return UIGraphicsImageRenderer(size: size).image { rendererContext in
self.setFill()
rendererContext.fill(CGRect(origin: .zero, size: size))
}
}
}
16 changes: 16 additions & 0 deletions Sources/CharcoalSwiftUI/Extensions/ConditionalViewModifier.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import SwiftUI

extension View {
kevinneko marked this conversation as resolved.
Show resolved Hide resolved
/// Applies the given transform if the given condition evaluates to `true`.
/// - Parameters:
/// - condition: The condition to evaluate.
/// - transform: The transform to apply to the source `View`.
/// - Returns: Either the original `View` or the modified `View` if the condition is `true`.
@ViewBuilder func `if`<Content: View>(_ condition: Bool, transform: (Self) -> Content) -> some View {
if condition {
transform(self)
} else {
self
}
}
}
162 changes: 162 additions & 0 deletions Sources/CharcoalUIKit/Components/Hints/HintView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
import UIKit

public class CharcoalHintView: UIView {
lazy var hStackView: UIStackView = {
let stackView = UIStackView()
stackView.axis = .horizontal
stackView.alignment = .center
stackView.spacing = 0
stackView.translatesAutoresizingMaskIntoConstraints = false
return stackView
}()

lazy var label: CharcoalTypography14 = {
let label = CharcoalTypography14()
label.numberOfLines = 0
label.translatesAutoresizingMaskIntoConstraints = false
label.textAlignment = .left
label.textColor = CharcoalAsset.ColorPaletteGenerated.text1.color
return label
}()

lazy var thumbnailImageView: UIImageView = {
let imageView = UIImageView()
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.contentMode = .scaleAspectFill
return imageView
}()

lazy var actionButton: CharcoalPrimarySButton = {
let button = CharcoalPrimarySButton()
return button
}()

let thumbnailImage: UIImage = CharcoalAsset.Images.info16.image

var action: CharcoalAction?

let text: String

/// The corner radius of the snackbar
let cornerRadius: CGFloat = 8

/// Padding around the bubble
let padding = UIEdgeInsets(top: 12, left: 16, bottom: 12, right: 16)

var gesture: CharcoalGesture?

public init(text: String, action: CharcoalAction? = nil) {
self.action = action
self.text = text
super.init(frame: .zero)
self.hStackView.spacing = 4
if let action = action {
actionButton.setTitle(action.title, for: .normal)
}
setupLayer()
}

@available(*, unavailable)
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

private func setupCapsuleShape() {
layer.backgroundColor = CharcoalAsset.ColorPaletteGenerated.surface3.color.cgColor
layer.masksToBounds = true
layer.cornerRadius = cornerRadius
layer.cornerCurve = .continuous
}

private func addThumbnailView() {
thumbnailImageView.image = thumbnailImage
hStackView.addArrangedSubview(thumbnailImageView)
NSLayoutConstraint.activate([
thumbnailImageView.widthAnchor.constraint(equalToConstant: 16),
thumbnailImageView.heightAnchor.constraint(equalToConstant: 16)
])
}

private func addTextLabel() {
hStackView.addArrangedSubview(label)
label.text = text
label.setContentHuggingPriority(.defaultLow, for: .horizontal)
label.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal)
}

private func addActionButton() {
if let _ = action {
actionButton.addTarget(self, action: #selector(actionButtonTapped), for: .touchUpInside)
hStackView.addArrangedSubview(actionButton)
actionButton.widthAnchor.constraint(equalToConstant: actionButton.intrinsicContentSize.width).isActive = true
}
}

private func setupLayer() {
// Setup Bubble Shape
setupCapsuleShape()

// Add HStack
addSubview(hStackView)
NSLayoutConstraint.activate([
hStackView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: padding.left),
hStackView.topAnchor.constraint(equalTo: topAnchor, constant: padding.top),
hStackView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -padding.bottom),
hStackView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -padding.right)
])


// Add thumbnail view
addThumbnailView()

// Add text label with padding view
addTextLabel()

// Add action button
addActionButton()
}

@objc func actionButtonTapped() {
action?.actionCallback()
}

/// Add gesture to this view
func addGesture(_ gesture: CharcoalGesture) {
self.gesture = gesture
addGestureRecognizer(gesture.gesture)
}
}

@available(iOS 17.0, *)
#Preview(traits: .sizeThatFitsLayout) {
let stackView = UIStackView()
stackView.axis = .vertical
stackView.distribution = .fill
stackView.alignment = .center
stackView.spacing = 8.0

stackView.widthAnchor.constraint(equalToConstant: 300).isActive = true

let snackbar = CharcoalHintView(text: "Hello World")
stackView.addArrangedSubview(snackbar)

let snackbar2 = CharcoalHintView(text: "ブックマークしました")
stackView.addArrangedSubview(snackbar2)
snackbar2.widthAnchor.constraint(equalTo: stackView.widthAnchor).isActive = true

let snackbar3 = CharcoalHintView(text: "ブックマークしました", action: CharcoalAction(title: "編集", actionCallback: {
print("編集 taped")
}))
stackView.addArrangedSubview(snackbar3)

let snackbar4 = CharcoalHintView(
text: "こんにちは",
action: CharcoalAction(title: "編集", actionCallback: {
print("編集 taped")
})
)
stackView.addArrangedSubview(snackbar4)
snackbar4.widthAnchor.constraint(equalTo: stackView.widthAnchor).isActive = true

return stackView
}
11 changes: 11 additions & 0 deletions Sources/CharcoalUIKit/Components/Toast/CharcoalAction.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
public typealias ActionCallback = () -> Void

public struct CharcoalAction {
kevinneko marked this conversation as resolved.
Show resolved Hide resolved
let title: String
let actionCallback: ActionCallback

public init(title: String, actionCallback: @escaping ActionCallback) {
self.title = title
self.actionCallback = actionCallback
}
}
78 changes: 78 additions & 0 deletions Sources/CharcoalUIKit/Components/Toast/CharcoalRubberGesture.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import UIKit

protocol CharcoalGesture {
var gesture: UIGestureRecognizer { get }
}

class CharcoalRubberGesture: NSObject, CharcoalGesture {
let screenEdge: CharcoalPopupViewEdge

var gesture: UIGestureRecognizer

var dragVelocity: CGPoint = .zero

var isDragging: Bool = false

var offset: CGSize = .zero

var dismiss: (() -> Void)?

init(screenEdge: CharcoalPopupViewEdge) {
self.screenEdge = screenEdge
gesture = UIPanGestureRecognizer()
super.init()
gesture.addTarget(self, action: #selector(handlePan(_:)))
}

@objc func handlePan(_ gesture: UIPanGestureRecognizer) {
guard let view = gesture.view else { return }

let translation = gesture.translation(in: gesture.view)
let velocity = gesture.velocity(in: gesture.view)
let translationInDirection = translation.y * screenEdge.direction
let movingVelocityInDirection = velocity.y * screenEdge.direction
let offsetInDirection = offset.height * screenEdge.direction

// Rubber band effect
let damping: CGFloat = 0.75
let initialSpringVelocity: CGFloat = 0.0
let duration: TimeInterval = 0.65

switch gesture.state {
case .began:
isDragging = true
case .changed:
dragVelocity = velocity
if translationInDirection < 0 {
offset = CGSize(width: 0, height: translation.y)
view.transform = CGAffineTransform(translationX: 0, y: translation.y)
} else {
let limit: CGFloat = 60
let dist = sqrt(translation.y * translation.y)
let factor = 1 / (dist / limit + 1)
offset = CGSize(width: 0, height: translation.y * factor)
view.transform = CGAffineTransform(translationX: 0, y: translation.y * factor)
}
case .ended, .cancelled:
isDragging = false
if offsetInDirection < -50 || movingVelocityInDirection < -100 {
// Dismiss
dismiss?()
} else {
UIView.animate(
withDuration: duration,
delay: 0,
usingSpringWithDamping: damping,
initialSpringVelocity: initialSpringVelocity,
options: [],
animations: {
view.transform = .identity
},
completion: nil
)
}
default:
break
}
}
}
Loading