Skip to content

Commit f2674dc

Browse files
committed
Adjust restore to return builder
1 parent dc32492 commit f2674dc

File tree

6 files changed

+75
-41
lines changed

6 files changed

+75
-41
lines changed

Core/Sources/ChatGPTChatTab/ChatGPTChatTab.swift

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,15 @@ public class ChatGPTChatTab: ChatTab {
2222

2323
struct Builder: ChatTabBuilder {
2424
var title: String
25-
var buildable: Bool { true }
2625
var customCommand: CustomCommand?
26+
var afterBuild: (ChatGPTChatTab) async -> Void = { _ in }
2727

28-
func build(store: StoreOf<ChatTabItem>) -> any ChatTab {
28+
func build(store: StoreOf<ChatTabItem>) async -> (any ChatTab)? {
2929
let tab = ChatGPTChatTab(store: store)
30-
Task {
31-
if let customCommand {
32-
try await tab.service.handleCustomCommand(customCommand)
33-
}
30+
if let customCommand {
31+
try? await tab.service.handleCustomCommand(customCommand)
3432
}
33+
await afterBuild(tab)
3534
return tab
3635
}
3736
}
@@ -54,17 +53,16 @@ public class ChatGPTChatTab: ChatTab {
5453

5554
public static func restore(
5655
from data: Data,
57-
store: StoreOf<ChatTabItem>,
5856
externalDependency: Void
59-
) async throws -> any ChatTab {
57+
) async throws -> any ChatTabBuilder {
6058
let state = try JSONDecoder().decode(RestorableState.self, from: data)
61-
let tab = ChatGPTChatTab(store: store)
62-
tab.service.configuration.overriding = state.configuration
63-
await tab.service.memory.mutateHistory { history in
64-
history = state.history
59+
let builder = Builder(title: "Chat") { @MainActor tab in
60+
tab.service.configuration.overriding = state.configuration
61+
await tab.service.memory.mutateHistory { history in
62+
history = state.history
63+
}
6564
}
66-
67-
return tab
65+
return builder
6866
}
6967

7068
public static func chatBuilders(externalDependency: Void) -> [ChatTabBuilder] {
@@ -84,7 +82,7 @@ public class ChatGPTChatTab: ChatTab {
8482
provider = .init(service: service)
8583
super.init(store: store)
8684
}
87-
85+
8886
public func start() {
8987
chatTabViewStore.send(.updateTitle("Chat"))
9088
provider.$history.sink { [weak self] _ in

Core/Sources/Service/GUI/GraphicalUserInterfaceController.swift

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ import Environment
77
import Preferences
88
import SuggestionWidget
99

10+
#if canImport(ChatTabPersistent)
11+
import ChatTabPersistent
12+
#endif
13+
1014
struct GUI: ReducerProtocol {
1115
struct State: Equatable {
1216
var suggestionWidgetState = WidgetFeature.State()
@@ -15,6 +19,17 @@ struct GUI: ReducerProtocol {
1519
get { suggestionWidgetState.chatPanelState.chatTapGroup }
1620
set { suggestionWidgetState.chatPanelState.chatTapGroup = newValue }
1721
}
22+
23+
#if canImport(ChatTabPersistent)
24+
var persistentState: ChatTabPersistent.State {
25+
get {
26+
.init(chatTabInfo: suggestionWidgetState.chatPanelState.chatTapGroup.tabInfo)
27+
}
28+
set {
29+
suggestionWidgetState.chatPanelState.chatTapGroup.tabInfo = newValue.chatTabInfo
30+
}
31+
}
32+
#endif
1833
}
1934

2035
enum Action {
@@ -23,6 +38,10 @@ struct GUI: ReducerProtocol {
2338
case sendCustomCommandToActiveChat(CustomCommand)
2439

2540
case suggestionWidget(WidgetFeature.Action)
41+
42+
#if canImport(ChatTabPersistent)
43+
case persistent(ChatTabPersistent.Action)
44+
#endif
2645
}
2746

2847
@Dependency(\.chatTabPool) var chatTabPool: ChatTabPool
@@ -65,6 +84,12 @@ struct GUI: ReducerProtocol {
6584
}
6685
}
6786

87+
#if canImport(ChatTabPersistent)
88+
Scope(state: \.persistentState, action: /Action.persistent) {
89+
ChatTabPersistent()
90+
}
91+
#endif
92+
6893
Reduce { state, action in
6994
switch action {
7095
case let .openChatPanel(forceDetach):
@@ -126,8 +151,22 @@ struct GUI: ReducerProtocol {
126151
}
127152
}
128153

154+
case .suggestionWidget(.chatPanel(.chatTab(_, .tabContentUpdated))):
155+
#if canImport(ChatTabPersistent)
156+
return .run { send in
157+
await send(.persistent(.persistChatTabs))
158+
}
159+
#else
160+
return .none
161+
#endif
162+
129163
case .suggestionWidget:
130164
return .none
165+
166+
#if canImport(ChatTabPersistent)
167+
case .persistent:
168+
return .none
169+
#endif
131170
}
132171
}
133172
}
@@ -213,28 +252,27 @@ extension ChatTabPool {
213252
@MainActor
214253
func createTab(
215254
from builder: ChatTabBuilder
216-
) -> (any ChatTab, ChatTabInfo)? {
255+
) async -> (any ChatTab, ChatTabInfo)? {
217256
let id = UUID().uuidString
218257
let info = ChatTabInfo(id: id, title: "")
219-
guard builder.buildable else { return nil }
220-
let chatTap = builder.build(store: createStore(id))
258+
guard let chatTap = await builder.build(store: createStore(id)) else { return nil }
221259
setTab(chatTap)
222260
return (chatTap, info)
223261
}
224262

225263
@MainActor
226264
func createTab(
227265
for kind: ChatTabKind?
228-
) -> (any ChatTab, ChatTabInfo)? {
266+
) async -> (any ChatTab, ChatTabInfo)? {
229267
let id = UUID().uuidString
230268
let info = ChatTabInfo(id: id, title: "")
231269
guard let builder = kind?.builder else {
232270
let chatTap = ChatGPTChatTab(store: createStore(id))
233271
setTab(chatTap)
234272
return (chatTap, info)
235273
}
236-
guard builder.buildable else { return nil }
237-
let chatTap = builder.build(store: createStore(id))
274+
275+
guard let chatTap = await builder.build(store: createStore(id)) else { return nil }
238276
setTab(chatTap)
239277
return (chatTap, info)
240278
}

Core/Sources/SuggestionWidget/ChatWindowView.swift

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ struct ChatTabBar: View {
225225
store.send(.createNewTapButtonClicked(kind: kind))
226226
}) {
227227
Text(kind.title)
228-
}.disabled(!kind.builder.buildable)
228+
}.disabled(kind.builder is DisabledChatTabBuilder)
229229
case let .folder(title, list):
230230
Menu {
231231
ForEach(0..<list.endIndex, id: \.self) { index in
@@ -364,9 +364,8 @@ class FakeChatTab: ChatTab {
364364

365365
struct Builder: ChatTabBuilder {
366366
var title: String = "Title"
367-
var buildable: Bool { true }
368367

369-
func build(store: StoreOf<ChatTabItem>) -> any ChatTab {
368+
func build(store: StoreOf<ChatTabItem>) async -> (any ChatTab)? {
370369
return FakeChatTab(store: store)
371370
}
372371
}
@@ -395,10 +394,9 @@ class FakeChatTab: ChatTab {
395394

396395
static func restore(
397396
from data: Data,
398-
store: StoreOf<ChatTabItem>,
399397
externalDependency: ()
400-
) async throws -> any ChatTab {
401-
return FakeChatTab(store: store)
398+
) async throws -> any ChatTabBuilder {
399+
return Builder()
402400
}
403401

404402
convenience init(id: String, title: String) {

Pro

Submodule Pro updated from 8ed1a2b to 010cee4

Tool/Sources/ChatTab/ChatTab.swift

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,8 @@ public protocol ChatTabType {
3636
/// Restore state
3737
static func restore(
3838
from data: Data,
39-
store: StoreOf<ChatTabItem>,
4039
externalDependency: ExternalDependency
41-
) async throws -> any ChatTab
40+
) async throws -> any ChatTabBuilder
4241
/// Whenever the body or menu is accessed, this method will be called.
4342
/// It will be called only once so long as you don't call it yourself.
4443
/// It will be called from MainActor.
@@ -57,8 +56,11 @@ open class BaseChatTab {
5756

5857
public var id: String { chatTabViewStore.id }
5958
public var title: String { chatTabViewStore.title }
59+
/// The store for chat tab info. You should only access it after `start` is called.
6060
public let chatTabStore: StoreOf<ChatTabItem>
61+
/// The view store for chat tab info. You should only access it after `start` is called.
6162
public let chatTabViewStore: ViewStoreOf<ChatTabItem>
63+
6264
private var didStart = false
6365

6466
public init(store: StoreOf<ChatTabItem>) {
@@ -109,18 +111,15 @@ open class BaseChatTab {
109111
public protocol ChatTabBuilder {
110112
/// A visible title for user.
111113
var title: String { get }
112-
/// whether the chat tab is buildable.
113-
var buildable: Bool { get }
114114
/// Build the chat tab.
115-
func build(store: StoreOf<ChatTabItem>) -> any ChatTab
115+
func build(store: StoreOf<ChatTabItem>) async -> (any ChatTab)?
116116
}
117117

118118
/// A chat tab builder that doesn't build.
119119
public struct DisabledChatTabBuilder: ChatTabBuilder {
120120
public var title: String
121-
public var buildable: Bool { false }
122-
public func build(store: StoreOf<ChatTabItem>) -> any ChatTab {
123-
EmptyChatTab(store: store)
121+
public func build(store: StoreOf<ChatTabItem>) async -> (any ChatTab)? {
122+
return nil
124123
}
125124

126125
public init(title: String) {
@@ -147,8 +146,7 @@ public class EmptyChatTab: ChatTab {
147146

148147
struct Builder: ChatTabBuilder {
149148
let title: String
150-
var buildable: Bool { true }
151-
func build(store: StoreOf<ChatTabItem>) -> any ChatTab {
149+
func build(store: StoreOf<ChatTabItem>) async -> (any ChatTab)? {
152150
EmptyChatTab(store: store)
153151
}
154152
}
@@ -174,10 +172,9 @@ public class EmptyChatTab: ChatTab {
174172

175173
public static func restore(
176174
from data: Data,
177-
store: StoreOf<ChatTabItem>,
178175
externalDependency: Void
179-
) async throws -> any ChatTab {
180-
return Builder(title: "Empty").build(store: store)
176+
) async throws -> any ChatTabBuilder {
177+
return Builder(title: "Empty")
181178
}
182179

183180
public convenience init(id: String) {

Tool/Sources/ChatTab/ChatTabItem.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ public struct ChatTabItem: ReducerProtocol {
1919
public enum Action: Equatable {
2020
case updateTitle(String)
2121
case openNewTab(AnyChatTabBuilder)
22+
case tabContentUpdated
2223
}
2324

2425
public init() {}
@@ -31,6 +32,8 @@ public struct ChatTabItem: ReducerProtocol {
3132
return .none
3233
case .openNewTab:
3334
return .none
35+
case .tabContentUpdated:
36+
return .none
3437
}
3538
}
3639
}

0 commit comments

Comments
 (0)