Skip to content

Commit 5bbdd1f

Browse files
committed
[Feat] TToast ์ž‘์„ฑ
1 parent ea1f7cc commit 5bbdd1f

File tree

2 files changed

+144
-0
lines changed

2 files changed

+144
-0
lines changed
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
//
2+
// TToastModifier.swift
3+
// DesignSystem
4+
//
5+
// Created by ๋ฐ•๋ฏผ์„œ on 2/3/25.
6+
// Copyright ยฉ 2025 yapp25thTeamTnT. All rights reserved.
7+
//
8+
9+
import SwiftUI
10+
11+
/// ํ† ์ŠคํŠธ ๋ฉ”์‹œ์ง€๋ฅผ ํ™”๋ฉด์— ํ‘œ์‹œํ•˜๋Š” ViewModifier
12+
/// - `isPresented` ๋ฐ”์ธ๋”ฉ์„ ํ†ตํ•ด ํ† ์ŠคํŠธ ๋ฉ”์‹œ์ง€์˜ ํ‘œ์‹œ ์—ฌ๋ถ€๋ฅผ ์ œ์–ด
13+
/// - ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์ ์šฉํ•˜์—ฌ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๋‚˜ํƒ€๋‚ฌ๋‹ค๊ฐ€ ์‚ฌ๋ผ์ง€๋Š” ํšจ๊ณผ
14+
public struct TToastViewModifier<InnerContent: View>: ViewModifier {
15+
/// ํ† ์ŠคํŠธ์— ํ‘œ์‹œ๋  ๋‚ด๋ถ€ ์ฝ˜ํ…์ธ  ํด๋กœ์ €
16+
private let innerContent: () -> InnerContent
17+
/// ํ† ์ŠคํŠธ ํ‘œ์‹œ ์—ฌ๋ถ€
18+
@Binding private var isPresented: Bool
19+
/// ํ† ์ŠคํŠธ๊ฐ€ ํ™”๋ฉด์— ๋ณด์ด๋Š” ์ƒํƒœ์ธ์ง€ ์—ฌ๋ถ€ (์• ๋‹ˆ๋ฉ”์ด์…˜์šฉ)
20+
@State private var isVisible: Bool = false
21+
22+
/// TToastViewModifier ์ดˆ๊ธฐํ™” ๋ฉ”์„œ๋“œ
23+
/// - Parameters:
24+
/// - isPresented: ํ† ์ŠคํŠธ ํ‘œ์‹œ ์—ฌ๋ถ€๋ฅผ ์ œ์–ดํ•˜๋Š” Binding
25+
/// - newContent: ํ† ์ŠคํŠธ์— ํ‘œ์‹œ๋  ๋‚ด๋ถ€ ์ฝ˜ํ…์ธ  ํด๋กœ์ €
26+
public init(
27+
isPresented: Binding<Bool>,
28+
newContent: @escaping () -> InnerContent
29+
) {
30+
self._isPresented = isPresented
31+
self.innerContent = newContent
32+
}
33+
34+
public func body(content: Content) -> some View {
35+
ZStack {
36+
// ๊ธฐ์กด ๋ทฐ
37+
content
38+
.onTapGesture {
39+
isPresented = false
40+
}
41+
42+
if isPresented {
43+
// ํ† ์ŠคํŠธ ๋ทฐ
44+
self.innerContent()
45+
.padding(.horizontal, 20)
46+
.padding(.bottom, 24)
47+
.opacity(isVisible ? 1 : 0)
48+
.transition(.move(edge: .bottom).combined(with: .opacity))
49+
.onAppear {
50+
showToast()
51+
}
52+
}
53+
}
54+
.animation(.easeInOut, value: isPresented)
55+
}
56+
57+
/// ํ† ์ŠคํŠธ ๋ฉ”์‹œ์ง€๋ฅผ ํ‘œ์‹œํ•˜๊ณ  ์ž๋™์œผ๋กœ ์‚ฌ๋ผ์ง€๋„๋ก ์ฒ˜๋ฆฌํ•˜๋Š” ํ•จ์ˆ˜
58+
private func showToast() {
59+
// ํŽ˜์ด๋“œ์ธ
60+
withAnimation(.easeInOut(duration: 0.3)) {
61+
isVisible = true
62+
}
63+
// 2์ดˆ๊ฐ„ ์œ ์ง€ - ์ž๋™์œผ๋กœ ์‚ฌ๋ผ์ง
64+
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
65+
// ํŽ˜์ด๋“œ ์•„์›ƒ
66+
withAnimation(.easeInOut(duration: 0.3)) {
67+
isVisible = false
68+
}
69+
// present ํ•ด์ œ
70+
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
71+
isPresented = false
72+
}
73+
}
74+
}
75+
}
76+
77+
public extension View {
78+
/// ํ† ์ŠคํŠธ ๋ฉ”์‹œ์ง€๋ฅผ ํ™”๋ฉด์— ํ‘œ์‹œํ•˜๋Š” ViewModifier
79+
///
80+
/// - `isPresented`: ํ† ์ŠคํŠธ์˜ ํ‘œ์‹œ ์—ฌ๋ถ€๋ฅผ ์ œ์–ดํ•˜๋Š” Binding.
81+
/// - `message`: ํ† ์ŠคํŠธ์— ํ‘œ์‹œํ•  ๋ฉ”์‹œ์ง€.
82+
/// - `leftView`: ํ† ์ŠคํŠธ ์ขŒ์ธก์— ์ถ”๊ฐ€ํ•  ์•„์ด์ฝ˜์ด๋‚˜ ๋ทฐ.
83+
func tToast<LeftView: View>(
84+
isPresented: Binding<Bool>,
85+
message: String,
86+
leftView: @escaping () -> LeftView
87+
) -> some View {
88+
self.modifier(
89+
TToastViewModifier(
90+
isPresented: isPresented,
91+
newContent: {
92+
TToastView(message: message, leftView: leftView)
93+
}
94+
)
95+
)
96+
}
97+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
//
2+
// TToastView.swift
3+
// DesignSystem
4+
//
5+
// Created by ๋ฐ•๋ฏผ์„œ on 2/3/25.
6+
// Copyright ยฉ 2025 yapp25thTeamTnT. All rights reserved.
7+
//
8+
9+
import SwiftUI
10+
11+
/// ์•ฑ ์ „๋ฐ˜์ ์œผ๋กœ ์‚ฌ์šฉ๋˜๋Š” ํ† ์ŠคํŠธ ๋ฉ”์‹œ์ง€ ๋ทฐ
12+
/// - ์งง์€ ์‹œ๊ฐ„ ๋™์•ˆ ํ•˜๋‹จ์— ๋‚˜ํƒ€๋‚ฌ๋‹ค๊ฐ€ ์‚ฌ๋ผ์ง€๋Š” UI ์ปดํฌ๋„ŒํŠธ.
13+
public struct TToastView<LeftView: View>: View {
14+
/// ํ† ์ŠคํŠธ ๋ฉ”์„ธ์ง€
15+
private let message: String
16+
/// ํ† ์ŠคํŠธ ์ขŒ์ธก ๋ทฐ
17+
private let leftView: () -> LeftView
18+
19+
/// TToastView ์ดˆ๊ธฐํ™” ๋ฉ”์„œ๋“œ
20+
/// - Parameters:
21+
/// - message: ํ‘œ์‹œํ•  ๋ฉ”์‹œ์ง€
22+
/// - leftView: ์ขŒ์ธก ์•„์ด์ฝ˜ ๋˜๋Š” ์ปค์Šคํ…€ ๋ทฐ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํด๋กœ์ €
23+
public init(message: String, leftView: @escaping () -> LeftView) {
24+
self.message = message
25+
self.leftView = leftView
26+
}
27+
28+
public var body: some View {
29+
VStack {
30+
Spacer()
31+
32+
HStack(spacing: 8) {
33+
leftView()
34+
35+
Text(message)
36+
.typographyStyle(.label1Medium, with: .neutral50)
37+
38+
Spacer()
39+
}
40+
.padding(.vertical, 16)
41+
.padding(.horizontal, 20)
42+
.frame(maxWidth: .infinity)
43+
.background(Color.neutral900.opacity(0.8))
44+
.clipShape(.rect(cornerRadius: 16))
45+
}
46+
}
47+
}

0 commit comments

Comments
ย (0)