import LChatCore import SwiftUI import UIKit // The full space list — everything the home screen elides: ALL active spaces // (favourites first, the rest below), standard List drag-to-reorder within // each group, and the manage context menu. Archived spaces stay hidden here // too (they live in the account — unarchive on the home page). struct SpaceListSheet: View { @EnvironmentObject var app: AppState @Environment(\.dismiss) private var dismiss let activeID: String? var onSelect: (SavedInstance) -> Void private var active: [SavedInstance] { app.instances.filter { !$0.isArchived } } private var starred: [SavedInstance] { active.filter(\.isStarred) } private var others: [SavedInstance] { active.filter { !$0.isStarred } } var body: some View { NavigationStack { List { if starred.isEmpty { Section { ForEach(active) { row($0) } .onMove { app.move(from: $0, to: $1) } } } else { // Each group drags independently (home's independent lists); // without these, starring ANYTHING killed reorder entirely. Section("Favourites") { ForEach(starred) { row($0) } .onMove { app.moveInGroup(starred: true, from: $0, to: $1) } } if !others.isEmpty { Section("More") { ForEach(others) { row($0) } .onMove { app.moveInGroup(starred: false, from: $0, to: $1) } } } } } .navigationTitle("Spaces") .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .confirmationAction) { Button("Done") { dismiss() } } } } } private func row(_ inst: SavedInstance) -> some View { Button { onSelect(inst) } label: { SpaceRow(instance: inst, active: inst.id == activeID, photo: app.serverAvatars[inst.id]) } .foregroundStyle(.primary) .contextMenu { SpaceMenuItems(instance: inst) } } } // One space: avatar, name, host subtitle — shared by the home screen's lists // (a trailing disclosure chevron: every row navigates) and the More sheet // (a checkmark on the active one instead). struct SpaceRow: View { let instance: SavedInstance let active: Bool var photo: UIImage? var chevron = false var body: some View { HStack(spacing: 12) { Avatar(name: instance.displayName, size: 36, photo: photo) VStack(alignment: .leading, spacing: 2) { Text(instance.displayName).font(.headline).lineLimit(1) // The host, unless the title already IS the host (no group // name yet) — no point showing it twice. if instance.displayName != instance.hostLabel { Text(instance.hostLabel).font(.caption).foregroundStyle(.secondary).lineLimit(1) } } Spacer() if chevron { Image(systemName: "chevron.right") .font(.footnote.weight(.semibold)) .foregroundStyle(.tertiary) } else if active { Image(systemName: "checkmark") .font(.subheadline.weight(.semibold)) .foregroundStyle(Color.accentColor) } } .contentShape(Rectangle()) } } // The manage menu shared by the home screen rows and the More sheet rows. struct SpaceMenuItems: View { @EnvironmentObject var app: AppState let instance: SavedInstance var body: some View { Button { app.toggleStar(instance) } label: { Label(instance.isStarred ? "Unstar" : "Star", systemImage: instance.isStarred ? "star.slash" : "star") } Button { app.toggleArchive(instance) } label: { Label(instance.isArchived ? "Unarchive" : "Archive", systemImage: instance.isArchived ? "tray.and.arrow.up" : "archivebox") } Button(role: .destructive) { app.remove(instance) } label: { Label("Remove", systemImage: "trash") } } }