eleven / messenger Public

Clone
git clone https://amadan.net/eleven/messenger

Plain git — no account needed to clone.

Download

Download this file

1import SwiftUI
2import LChatCore
3
4// 🤖 iOS host for Eleven's native onboarding conversation (setup / welcome):
5// owns the model's lifecycle and wires the finish chips' thread hop into the
6// navigation path. Models are cached per thread so leaving and returning
7// resumes the same run (the flow itself also resumes from recorded state).
8struct ElevenChatScreen: View {
9 let instance: SavedInstance
10 let thread: ChatThread
11 @ObservedObject var store: ThreadStore
12 @Binding var path: [Route]
13 @State private var model: ElevenConversationModel?
14 @State private var showDiscover = false
15 @State private var showQuickForm = false
16 @ScaledMetric(relativeTo: .body) private var chatFontSize: CGFloat = 17
17 @AppStorage("nativeTheme") private var themeName = "classic"
18
19 var body: some View {
20 Group {
21 if let model {
22 ElevenChatView(model: model, theme: .named(themeName))
23 .environment(\.chatFontSize, chatFontSize)
24 } else {
25 ProgressView()
26 }
27 }
28 .navigationTitle(thread.title)
29 .navigationBarTitleDisplayMode(.inline)
30 .sheet(isPresented: $showDiscover) {
31 // The community directory (shared view; web: showDiscover) — the
32 // welcome finish's "Browse open groups" chip lands here.
33 NavigationStack {
34 DiscoverGroupsView(store: store) { id in
35 showDiscover = false
36 path.append(.thread(id))
37 }
38 }
39 }
40 .sheet(isPresented: $showQuickForm) {
41 // "Fill in a form instead" — the whole conversation's questions at
42 // once; submitting fast-fills the flow's records and it resumes.
43 if let model {
44 ElevenQuickFormView(model: model)
45 }
46 }
47 .onAppear {
48 guard model == nil else { return }
49 let m = ElevenConversationCache.shared.model(for: instance, thread: thread,
50 myUserId: store.myUserId)
51 m?.openQuickForm = { showQuickForm = true }
52 m?.openThread = { id in path.append(.thread(id)) }
53 m?.openAdmin = {
54 Task { @MainActor in
55 if let id = await store.openOrCreateAppThread(app: "admin", title: "Admin") {
56 path.append(.thread(id))
57 }
58 }
59 }
60 m?.openDiscover = { showDiscover = true }
61 // Outgoing payloads stamp the SavedInstance's name — persist a
62 // flow rename, the way ServerSettingsSheet persists a manual one.
63 m?.onNameSet = { name in
64 var instances = InstancesStore.load()
65 if let i = instances.firstIndex(where: { $0.id == instance.id }) {
66 instances[i].screenName = name
67 InstancesStore.save(instances)
68 }
69 }
70 m?.start(roster: store.roster, threads: store.threads)
71 model = m
72 }
73 }
74}
75