Skip to content

Commit f546302

Browse files
committed
Update toast
1 parent 05fd674 commit f546302

4 files changed

Lines changed: 115 additions & 9 deletions

File tree

CustomSuggestionService.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
/* Begin PBXBuildFile section */
1010
C80AC8F32C274ADD00669BDE /* FIMModelEdit.swift in Sources */ = {isa = PBXBuildFile; fileRef = C80AC8F12C274ADD00669BDE /* FIMModelEdit.swift */; };
1111
C80AC8F42C274ADD00669BDE /* FIMModelEditView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C80AC8F22C274ADD00669BDE /* FIMModelEditView.swift */; };
12+
C813647A2CA29924000E2237 /* HandleToast.swift in Sources */ = {isa = PBXBuildFile; fileRef = C81364792CA29924000E2237 /* HandleToast.swift */; };
1213
C83B83AF2B7DD261007B4442 /* Dependency.swift in Sources */ = {isa = PBXBuildFile; fileRef = C83B83AE2B7DD261007B4442 /* Dependency.swift */; };
1314
C84697512B7B7B3700B8B840 /* TestFieldView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C84697502B7B7B3700B8B840 /* TestFieldView.swift */; };
1415
C84697542B7B8B8300B8B840 /* STTextView in Frameworks */ = {isa = PBXBuildFile; productRef = C84697532B7B8B8300B8B840 /* STTextView */; };
@@ -71,6 +72,7 @@
7172
/* Begin PBXFileReference section */
7273
C80AC8F12C274ADD00669BDE /* FIMModelEdit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FIMModelEdit.swift; sourceTree = "<group>"; };
7374
C80AC8F22C274ADD00669BDE /* FIMModelEditView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FIMModelEditView.swift; sourceTree = "<group>"; };
75+
C81364792CA29924000E2237 /* HandleToast.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HandleToast.swift; sourceTree = "<group>"; };
7476
C81547D92B8737DF002203B3 /* LICENSE */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE; sourceTree = "<group>"; };
7577
C81547DB2B873DC1002203B3 /* appcast.xml */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = appcast.xml; sourceTree = "<group>"; };
7678
C83B83AE2B7DD261007B4442 /* Dependency.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Dependency.swift; sourceTree = "<group>"; };
@@ -259,6 +261,7 @@
259261
isa = PBXGroup;
260262
children = (
261263
C8EA62D42B6BE4BE00E081FC /* Toast.swift */,
264+
C81364792CA29924000E2237 /* HandleToast.swift */,
262265
);
263266
path = Toast;
264267
sourceTree = "<group>";
@@ -397,6 +400,7 @@
397400
C8EA62D62B6BE5FD00E081FC /* ChatModelEdit.swift in Sources */,
398401
C83B83AF2B7DD261007B4442 /* Dependency.swift in Sources */,
399402
C8D0114C2B59912700219412 /* CustomSuggestionServiceApp.swift in Sources */,
403+
C813647A2CA29924000E2237 /* HandleToast.swift in Sources */,
400404
C8774F482B83A009008FF699 /* CompletionModelEdit.swift in Sources */,
401405
C89BA4BC2B861DE4008801C5 /* UpdaterChecker.swift in Sources */,
402406
C8EA62DC2B6BE60500E081FC /* APIKeySubmission.swift in Sources */,

CustomSuggestionService/ContentView.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ struct ContentView: View {
125125
}
126126
}
127127
}
128+
.handleToast()
128129
}
129130
}
130131

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import Dependencies
2+
import SwiftUI
3+
4+
struct ToastHandler: View {
5+
@ObservedObject var toastController: ToastController
6+
let namespace: String?
7+
8+
init(toastController: ToastController, namespace: String?) {
9+
_toastController = .init(wrappedValue: toastController)
10+
self.namespace = namespace
11+
}
12+
13+
var body: some View {
14+
VStack(spacing: 4) {
15+
ForEach(toastController.messages) { message in
16+
if let n = message.namespace, n != namespace {
17+
EmptyView()
18+
} else {
19+
message.content
20+
.foregroundColor(.white)
21+
.padding(8)
22+
.background({
23+
switch message.type {
24+
case .info: return Color.accentColor
25+
case .error: return Color(nsColor: .systemRed)
26+
case .warning: return Color(nsColor: .systemOrange)
27+
}
28+
}() as Color, in: RoundedRectangle(cornerRadius: 8))
29+
.shadow(color: Color.black.opacity(0.2), radius: 4)
30+
}
31+
}
32+
}
33+
.padding()
34+
.allowsHitTesting(false)
35+
}
36+
}
37+
38+
extension View {
39+
func handleToast(namespace: String? = nil) -> some View {
40+
@Dependency(\.toastController) var toastController
41+
return overlay(alignment: .bottom) {
42+
ToastHandler(toastController: toastController, namespace: namespace)
43+
}.environment(\.toast) { [toastController] content, type in
44+
toastController.toast(content: content, type: type, namespace: namespace)
45+
}
46+
}
47+
}
48+

CustomSuggestionService/Toast/Toast.swift

Lines changed: 62 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,18 +30,52 @@ public extension DependencyValues {
3030
set { self[ToastControllerDependencyKey.self] = newValue }
3131
}
3232

33-
var toast: (String, ToastType) -> Void { toastController.toast }
33+
var toast: (String, ToastType) -> Void {
34+
return { content, type in
35+
toastController.toast(content: content, type: type, namespace: nil)
36+
}
37+
}
38+
39+
var namespacedToast: (String, ToastType, String) -> Void {
40+
return {
41+
content, type, namespace in
42+
toastController.toast(content: content, type: type, namespace: namespace)
43+
}
44+
}
3445
}
3546

3647
public class ToastController: ObservableObject {
3748
public struct Message: Identifiable, Equatable {
49+
public struct MessageButton: Equatable {
50+
public static func == (lhs: Self, rhs: Self) -> Bool {
51+
lhs.label == rhs.label
52+
}
53+
54+
public var label: Text
55+
public var action: () -> Void
56+
public init(label: Text, action: @escaping () -> Void) {
57+
self.label = label
58+
self.action = action
59+
}
60+
}
61+
62+
public var namespace: String?
3863
public var id: UUID
3964
public var type: ToastType
4065
public var content: Text
41-
public init(id: UUID, type: ToastType, content: Text) {
66+
public var buttons: [MessageButton]
67+
public init(
68+
id: UUID,
69+
type: ToastType,
70+
namespace: String? = nil,
71+
content: Text,
72+
buttons: [MessageButton] = []
73+
) {
74+
self.namespace = namespace
4275
self.id = id
4376
self.type = type
4477
self.content = content
78+
self.buttons = buttons
4579
}
4680
}
4781

@@ -51,16 +85,35 @@ public class ToastController: ObservableObject {
5185
self.messages = messages
5286
}
5387

54-
public func toast(content: String, type: ToastType) {
88+
public func toast(
89+
content: String,
90+
type: ToastType,
91+
namespace: String? = nil,
92+
buttons: [Message.MessageButton] = [],
93+
duration: TimeInterval = 4
94+
) {
5595
let id = UUID()
56-
let message = Message(id: id, type: type, content: Text(content))
96+
let message = Message(
97+
id: id,
98+
type: type,
99+
namespace: namespace,
100+
content: Text(content),
101+
buttons: buttons.map { b in
102+
Message.MessageButton(label: b.label, action: { [weak self] in
103+
b.action()
104+
withAnimation(.easeInOut(duration: 0.2)) {
105+
self?.messages.removeAll { $0.id == id }
106+
}
107+
})
108+
}
109+
)
57110

58111
Task { @MainActor in
59112
withAnimation(.easeInOut(duration: 0.2)) {
60113
messages.append(message)
61114
messages = messages.suffix(3)
62115
}
63-
try await Task.sleep(nanoseconds: 4_000_000_000)
116+
try await Task.sleep(nanoseconds: UInt64(duration * 1_000_000_000))
64117
withAnimation(.easeInOut(duration: 0.2)) {
65118
messages.removeAll { $0.id == id }
66119
}
@@ -85,7 +138,7 @@ public struct Toast {
85138
public enum Action: Equatable {
86139
case start
87140
case updateMessages([Message])
88-
case toast(String, ToastType)
141+
case toast(String, ToastType, String?)
89142
}
90143

91144
@Dependency(\.toastController) var toastController
@@ -94,7 +147,7 @@ public struct Toast {
94147

95148
public init() {}
96149

97-
public var body: some Reducer<State, Action> {
150+
public var body: some ReducerOf<Self> {
98151
Reduce { state, action in
99152
switch action {
100153
case .start:
@@ -117,8 +170,8 @@ public struct Toast {
117170
case let .updateMessages(messages):
118171
state.messages = messages
119172
return .none
120-
case let .toast(content, type):
121-
toastController.toast(content: content, type: type)
173+
case let .toast(content, type, namespace):
174+
toastController.toast(content: content, type: type, namespace: namespace)
122175
return .none
123176
}
124177
}

0 commit comments

Comments
 (0)