summaryrefslogtreecommitdiff
path: root/Hutch/Views
diff options
context:
space:
mode:
Diffstat (limited to 'Hutch/Views')
-rw-r--r--Hutch/Views/More/AccountSwitcherView.swift92
-rw-r--r--Hutch/Views/More/AddAccountView.swift59
-rw-r--r--Hutch/Views/More/MoreView.swift16
3 files changed, 167 insertions, 0 deletions
diff --git a/Hutch/Views/More/AccountSwitcherView.swift b/Hutch/Views/More/AccountSwitcherView.swift
new file mode 100644
index 0000000..6fe3c28
--- /dev/null
+++ b/Hutch/Views/More/AccountSwitcherView.swift
@@ -0,0 +1,92 @@
+import SwiftUI
+
+struct AccountSwitcherView: View {
+ @Environment(AppState.self) private var appState
+ @Environment(\.dismiss) private var dismiss
+
+ @State private var showAddAccount = false
+ @State private var isSwitching = false
+ @State private var switchError: String?
+
+ var body: some View {
+ NavigationStack {
+ List {
+ Section {
+ ForEach(appState.accounts) { account in
+ Button {
+ guard account.id != appState.activeAccountID else { return }
+ switchTo(account)
+ } label: {
+ HStack {
+ Text(account.username)
+ .foregroundStyle(.primary)
+ Spacer()
+ if account.id == appState.activeAccountID {
+ Image(systemName: "checkmark")
+ .foregroundStyle(.tint)
+ }
+ }
+ }
+ .disabled(isSwitching)
+ }
+ .onDelete { indexSet in
+ for index in indexSet {
+ let account = appState.accounts[index]
+ Task { await appState.removeAccount(id: account.id) }
+ }
+ }
+ }
+
+ Section {
+ Button {
+ showAddAccount = true
+ } label: {
+ Label("Add Account", systemImage: "plus.circle")
+ }
+ .disabled(isSwitching)
+ }
+ }
+ .navigationTitle("Accounts")
+ .navigationBarTitleDisplayMode(.inline)
+ .toolbar {
+ ToolbarItem(placement: .confirmationAction) {
+ Button("Done") { dismiss() }
+ }
+ }
+ .overlay {
+ if isSwitching {
+ ZStack {
+ Color.black.opacity(0.25).ignoresSafeArea()
+ ProgressView("Switching…")
+ .padding()
+ .background(.regularMaterial, in: RoundedRectangle(cornerRadius: 12))
+ }
+ }
+ }
+ .alert("Switch Failed", isPresented: Binding(
+ get: { switchError != nil },
+ set: { if !$0 { switchError = nil } }
+ )) {
+ Button("OK") { switchError = nil }
+ } message: {
+ Text(switchError ?? "")
+ }
+ .sheet(isPresented: $showAddAccount) {
+ AddAccountView()
+ }
+ }
+ }
+
+ private func switchTo(_ account: AccountEntry) {
+ isSwitching = true
+ Task {
+ do {
+ try await appState.switchAccount(to: account.id)
+ dismiss()
+ } catch {
+ switchError = error.localizedDescription
+ }
+ isSwitching = false
+ }
+ }
+}
diff --git a/Hutch/Views/More/AddAccountView.swift b/Hutch/Views/More/AddAccountView.swift
new file mode 100644
index 0000000..cfaa2b2
--- /dev/null
+++ b/Hutch/Views/More/AddAccountView.swift
@@ -0,0 +1,59 @@
+import SwiftUI
+
+struct AddAccountView: View {
+ @Environment(AppState.self) private var appState
+ @Environment(\.dismiss) private var dismiss
+
+ @State private var token = ""
+ @State private var isConnecting = false
+ @State private var errorMessage: String?
+
+ var body: some View {
+ NavigationStack {
+ Form {
+ Section {
+ SecureField("Personal Access Token", text: $token)
+ .autocorrectionDisabled()
+ .textInputAutocapitalization(.never)
+ } footer: {
+ Text("Generate a token at meta.sr.ht → OAuth2 clients.")
+ }
+
+ if let errorMessage {
+ Section {
+ Text(errorMessage)
+ .foregroundStyle(.red)
+ }
+ }
+ }
+ .navigationTitle("Add Account")
+ .navigationBarTitleDisplayMode(.inline)
+ .toolbar {
+ ToolbarItem(placement: .cancellationAction) {
+ Button("Cancel") { dismiss() }
+ .disabled(isConnecting)
+ }
+ ToolbarItem(placement: .confirmationAction) {
+ Button("Connect") { connect() }
+ .disabled(token.trimmingCharacters(in: .whitespaces).isEmpty || isConnecting)
+ }
+ }
+ .interactiveDismissDisabled(isConnecting)
+ }
+ }
+
+ private func connect() {
+ isConnecting = true
+ errorMessage = nil
+ let trimmed = token.trimmingCharacters(in: .whitespaces)
+ Task {
+ do {
+ try await appState.addAccount(token: trimmed)
+ dismiss()
+ } catch {
+ errorMessage = error.localizedDescription
+ }
+ isConnecting = false
+ }
+ }
+}
diff --git a/Hutch/Views/More/MoreView.swift b/Hutch/Views/More/MoreView.swift
index b7c5576..c981432 100644
--- a/Hutch/Views/More/MoreView.swift
+++ b/Hutch/Views/More/MoreView.swift
@@ -1,12 +1,16 @@
import SwiftUI
struct MoreView: View {
+ @Environment(AppState.self) private var appState
+
private let unsupportedLinks: [(title: String, url: URL)] = [
("chat.sr.ht", URL(string: "https://chat.sr.ht")!),
("man.sr.ht", URL(string: "https://man.sr.ht")!),
("srht.site", URL(string: "https://srht.site")!)
]
+ @State private var showAccountSwitcher = false
+
var body: some View {
List {
Section {
@@ -36,5 +40,17 @@ struct MoreView: View {
}
}
.navigationTitle("More")
+ .toolbar {
+ ToolbarItem(placement: .topBarTrailing) {
+ Button {
+ showAccountSwitcher = true
+ } label: {
+ Image(systemName: "person.crop.circle")
+ }
+ }
+ }
+ .sheet(isPresented: $showAccountSwitcher) {
+ AccountSwitcherView()
+ }
}
}