Skip to content

Commit

Permalink
[#249] Toast 수정 및 Haptic 추가
Browse files Browse the repository at this point in the history
  • Loading branch information
chongin12 committed Dec 27, 2023
1 parent 3cb76ff commit d3d1a98
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 32 deletions.
29 changes: 29 additions & 0 deletions YDS-Essential/Source/HapticManager.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//
// HapticManager.swift
// YDS
//
// Created by 정종인 on 12/25/23.
//

import UIKit

public class HapticManager {
public static let instance = HapticManager()
private init() {}

public func notification(type: UINotificationFeedbackGenerator.FeedbackType) {
let generator = UINotificationFeedbackGenerator()
generator.notificationOccurred(type)
}

public func impact(style: UIImpactFeedbackGenerator.FeedbackStyle) {
let generator = UIImpactFeedbackGenerator(style: style)
generator.impactOccurred()
}
}

/*
Haptic Manager 사용 방법
HapticManager.instance.notification(type: .success)
HapticManager.instance.impact(style: .soft)
*/
13 changes: 9 additions & 4 deletions YDS-Storybook/SwiftUI/Components/ToastPageView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ struct ToastPageView: View {

@State var text: String? = "Toast"
@State var durationIndex: Int = 0
@State var isShowing: Bool = false
@State var hapticIndex: Int = 0

var body: some View {
StorybookPageView(
Expand All @@ -26,21 +26,26 @@ struct ToastPageView: View {
),
Option.enum(
description: "duration",
cases: YDSToast.ToastDuration.allCases,
cases: YDSToastModel.ToastDuration.allCases,
selectedIndex: $durationIndex
),
Option.enum(
description: "haptic",
cases: YDSToastModel.HapticType.allCases,
selectedIndex: $hapticIndex
)
]
)
.navigationTitle(title)
.overlay(alignment: .bottom) {
Button(action: { // 버튼은 추후 YDSButton 추가 이후에 수정 예정
isShowing = true
YDSToast(text ?? "", duration: .allCases[durationIndex], haptic: .allCases[hapticIndex])
}, label: {
Text("토스트 생성!")
})
.padding()
}
.ydsToast($text, isShowing: $isShowing)
.registerYDSToast()
}
}

Expand Down
97 changes: 69 additions & 28 deletions YDS-SwiftUI/Source/Component/YDSToast.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,17 @@
import SwiftUI
import UIKit
import YDS_Essential
import Combine
/*
YDSToast 사용 방법
1. 최상단 뷰에 .registerYDSToast() Modifier를 붙여준다.
2. toast를 띄우고 싶을 때 YDSToast()를 불러준다.
*/

public struct YDSToast: Equatable {
public struct YDSToastModel: Equatable {
let text: String
let duration: ToastDuration
let haptic: HapticType
public enum ToastDuration: CaseIterable {
case short
case long
Expand All @@ -25,6 +32,30 @@ public struct YDSToast: Equatable {
}
}
}
public enum HapticType: CaseIterable {
case success
case failed
case none
}
var playHaptic: () -> Void {
switch haptic {
case .success: {
HapticManager.instance.notification(type: .success)
}
case .failed: {
HapticManager.instance.notification(type: .warning)
}
case .none: {}
}
}
}

public func YDSToast(
_ text: String,
duration: YDSToastModel.ToastDuration = .short,
haptic: YDSToastModel.HapticType = .none
) {
YDSToastHelper.shared.enqueueToast(YDSToastModel(text: text, duration: duration, haptic: haptic))
}

public struct YDSToastView: View {
Expand All @@ -44,43 +75,53 @@ public struct YDSToastView: View {
}
}

public struct YDSToastModifier: ViewModifier {
@Binding public var isShowing: Bool
@Binding public var toast: YDSToast
public func body(content: Content) -> some View {
private class YDSToastHelper: ObservableObject {
static let shared = YDSToastHelper()
@Published var isShowing: Bool = false
@Published var showingToast: YDSToastModel?
private let subject = PassthroughSubject<YDSToastModel, Never>()
private var cancellables = Set<AnyCancellable>()
init() {
initSubscription()
}
private func initSubscription() {
subject
.receive(on: RunLoop.main)
.sink { [weak self] toast in
self?.isShowing = false
self?.isShowing = true
self?.showingToast = toast
toast.playHaptic()
DispatchQueue.main.asyncAfter(deadline: .now() + toast.duration.value) {
self?.isShowing = false
self?.showingToast = nil
}
}
.store(in: &cancellables)
}
func enqueueToast(_ toast: YDSToastModel) {
subject.send(toast)
}
}

struct YDSToastModifier: ViewModifier {
@StateObject private var toastHelper = YDSToastHelper.shared
func body(content: Content) -> some View {
content
.overlay(alignment: .bottom) {
if isShowing {
if toastHelper.isShowing, let toast = toastHelper.showingToast {
YDSToastView(toast.text)
.opacity(isShowing ? 1.0 : 0.0)
}
}
.onChange(of: isShowing) { value in
if value {
DispatchQueue.main.asyncAfter(deadline: .now() + toast.duration.value) {
isShowing = false
}
.opacity(toastHelper.isShowing ? 1.0 : 0.0)
}
}
.animation(.easeInOut, value: isShowing)
.animation(.easeInOut, value: toastHelper.isShowing)
}
}

extension View {
public func ydsToast(
_ text: Binding<String?>,
duration: YDSToast.ToastDuration = .short,
isShowing: Binding<Bool>
) -> some View {
public func registerYDSToast() -> some View {
self.modifier(
YDSToastModifier(
isShowing: isShowing,
toast: .init(get: {
YDSToast(text: text.wrappedValue ?? "", duration: duration)
}, set: { ydsToast in
text.wrappedValue = ydsToast.text
})
)
YDSToastModifier()
)
}
}
4 changes: 4 additions & 0 deletions YDS.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@
5A10B1B62A8F5C8500139E89 /* SwiftUIYDSIconArray.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A10B1B52A8F5C8500139E89 /* SwiftUIYDSIconArray.swift */; };
5A10B1B82A8F5FFF00139E89 /* IconPageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A10B1B72A8F5FFF00139E89 /* IconPageView.swift */; };
6CA05E822A90846B00B07920 /* SwiftUIYDSColorArray.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CA05E812A90846B00B07920 /* SwiftUIYDSColorArray.swift */; };
6F124C632B399953004187E6 /* HapticManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F124C612B399753004187E6 /* HapticManager.swift */; };
6F2D527B2A79446000BAF200 /* ColorPageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F2D527A2A79446000BAF200 /* ColorPageView.swift */; };
6F2D527D2A7944D800BAF200 /* PageListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F2D527C2A7944D800BAF200 /* PageListView.swift */; };
6F3C1EEE2A7A8573003D0D06 /* YDS_Essential.h in Headers */ = {isa = PBXBuildFile; fileRef = 6F3C1EED2A7A8573003D0D06 /* YDS_Essential.h */; settings = {ATTRIBUTES = (Public, ); }; };
Expand Down Expand Up @@ -329,6 +330,7 @@
5A10B1B52A8F5C8500139E89 /* SwiftUIYDSIconArray.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftUIYDSIconArray.swift; sourceTree = "<group>"; };
5A10B1B72A8F5FFF00139E89 /* IconPageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IconPageView.swift; sourceTree = "<group>"; };
6CA05E812A90846B00B07920 /* SwiftUIYDSColorArray.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftUIYDSColorArray.swift; sourceTree = "<group>"; };
6F124C612B399753004187E6 /* HapticManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HapticManager.swift; sourceTree = "<group>"; };
6F2D527A2A79446000BAF200 /* ColorPageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorPageView.swift; sourceTree = "<group>"; };
6F2D527C2A7944D800BAF200 /* PageListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PageListView.swift; sourceTree = "<group>"; };
6F3C1EEB2A7A8572003D0D06 /* YDS_Essential.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = YDS_Essential.framework; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -776,6 +778,7 @@
6F3C1F132A7A9616003D0D06 /* Source */ = {
isa = PBXGroup;
children = (
6F124C612B399753004187E6 /* HapticManager.swift */,
6F95FE5B2A768CAF00B398CF /* YDSBundle.swift */,
6F3C1EFF2A7A8843003D0D06 /* Rule */,
6F3C1EFE2A7A8839003D0D06 /* Foundation */,
Expand Down Expand Up @@ -1343,6 +1346,7 @@
buildActionMask = 2147483647;
files = (
6F3C1F122A7A9428003D0D06 /* YDSConstant.swift in Sources */,
6F124C632B399953004187E6 /* HapticManager.swift in Sources */,
6F3C1F0C2A7A8EC6003D0D06 /* YDSBundle.swift in Sources */,
6F3C1F112A7A9428003D0D06 /* YDSAnimation.swift in Sources */,
6F3C1F102A7A9428003D0D06 /* YDSScreenSize.swift in Sources */,
Expand Down

0 comments on commit d3d1a98

Please sign in to comment.