eleven / ocho Public

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

Plain git — no account needed to clone.

Download

Download this file

1import LChatCore
2import SwiftUI
3
4// 🤖 Spaces ▸ Add from Link…: paste any Eleven invite link and the space joins
5// this Mac NATIVELY — SpaceClaim handles all three link shapes (member/setup
6// invites, DM invites, add-device links) with no webview; the secret in the
7// #fragment never reaches any server. addInstance persists the identity in
8// the Keychain, selects the space, and pushes it to the member's Eleven
9// account (home vault), so it follows them to every signed-in device.
10struct AddFromLinkSheet: View {
11 @EnvironmentObject var app: MacAppState
12 @Environment(\.dismiss) private var dismiss
13 @State private var link = ""
14 @State private var busy = false
15 @State private var error: String?
16 @State private var hint: String?
17
18 /// The browser handoff's pre-fill (onOpenURL stashes the validated link;
19 /// see LChatMacApp): consumed once, so a later manual open starts blank.
20 /// The locked pane's rungs stash contextual guidance the same way.
21 private func consumePendingLink() {
22 if let pending = app.pendingAddLink {
23 link = pending
24 app.pendingAddLink = nil
25 }
26 if let h = app.addFromLinkHint {
27 hint = h
28 app.addFromLinkHint = nil
29 }
30 }
31
32 var body: some View {
33 VStack(alignment: .leading, spacing: 12) {
34 Text("Add a space from a link")
35 .font(.headline)
36 Text(hint ?? "Paste an invite link — the space joins this Mac and syncs to your Eleven account.")
37 .font(.callout)
38 .foregroundStyle(.secondary)
39 .fixedSize(horizontal: false, vertical: true)
40 TextField("https://…/join/…", text: $link)
41 .textFieldStyle(.roundedBorder)
42 .disabled(busy)
43 .onSubmit(add)
44 if let error {
45 Text(error)
46 .font(.footnote)
47 .foregroundStyle(.red)
48 .fixedSize(horizontal: false, vertical: true)
49 }
50 HStack {
51 Button("Cancel") { dismiss() }
52 .keyboardShortcut(.cancelAction)
53 .disabled(busy)
54 Spacer()
55 Button {
56 add()
57 } label: {
58 HStack(spacing: 6) {
59 if busy { ProgressView().controlSize(.small) }
60 Text(busy ? "Joining…" : "Add Space")
61 }
62 }
63 .buttonStyle(.borderedProminent)
64 .keyboardShortcut(.defaultAction)
65 .disabled(busy || parseJoinLink(link.trimmingCharacters(in: .whitespacesAndNewlines)) == nil)
66 }
67 }
68 .padding(20)
69 .frame(width: 440)
70 .onAppear(perform: consumePendingLink)
71 // A handoff can land while the sheet is already up (a second click
72 // in the browser) — take the newest link in place.
73 .onChange(of: app.pendingAddLink) { _, pending in
74 if pending != nil, !busy { consumePendingLink() }
75 }
76 }
77
78 private func add() {
79 let trimmed = link.trimmingCharacters(in: .whitespacesAndNewlines)
80 guard !busy, parseJoinLink(trimmed) != nil else {
81 if !trimmed.isEmpty { error = "That doesn't look like an Eleven invite link." }
82 return
83 }
84 busy = true
85 error = nil
86 Task { @MainActor in
87 do {
88 // Carry the name you already go by; an add-device link's own
89 // "~name" (or "Me") wins inside the claim when this is empty.
90 let screenName = app.instancesInRailOrder().first(where: { !$0.isArchived })?.screenName
91 ?? app.instances.first?.screenName ?? ""
92 let inst = try await SpaceClaim.claim(setupLink: trimmed, screenName: screenName)
93 app.addInstance(inst) // Keychain + rail + select + vault push
94 dismiss()
95 } catch {
96 self.error = (error as? LocalizedError)?.errorDescription
97 ?? "Couldn't add that space."
98 busy = false
99 }
100 }
101 }
102}
103