another.im-ios/AnotherIM/View/Main/Contacts/ContactsScreen.swift

201 lines
5.9 KiB
Swift
Raw Normal View History

import SwiftUI
struct ContactsScreen: View {
@Environment(\.router) var router
@EnvironmentObject var clientsStore: ClientsStore
var body: some View {
ZStack {
// Background color
Color.Material.Background.light
.ignoresSafeArea()
// Content
VStack(spacing: 0) {
// Header
SharedNavigationBar(
centerText: .init(text: L10n.Contacts.title),
rightButton: .init(
image: Image(systemName: "plus"),
action: {
router.showScreen(.fullScreenCover) { _ in
AddContactOrChannelScreen()
}
}
)
)
// Contacts list
2024-10-20 18:46:31 +00:00
if !clientsStore.actualRosters.isEmpty {
List {
ForEach(elements.indices, id: \.self) { index in
let element = elements[index]
if let roster = element as? Roster {
ContactsScreenRow(
roster: roster
)
} else if let bareJid = element as? String {
SharedSectionTitle(text: bareJid)
}
}
}
2024-10-20 18:46:31 +00:00
.listStyle(.plain)
.background(Color.Material.Background.light)
} else {
Spacer()
}
}
2024-10-20 18:45:53 +00:00
}
}
private var elements: [Any] {
if clientsStore.clients.filter({ $0.credentials.isActive }).count == 1 {
return clientsStore.actualRosters
} else {
var result: [Any] = []
for roster in clientsStore.actualRosters {
if result.isEmpty {
result.append(roster.bareJid)
} else if let last = result.last as? Roster, last.bareJid != roster.bareJid {
result.append(roster.bareJid)
}
result.append(roster)
}
return result
}
}
}
private struct ContactsScreenRow: View {
@Environment(\.router) var router
@EnvironmentObject var clientsStore: ClientsStore
var roster: Roster
var body: some View {
SharedListRow(
iconType: .charCircle(roster.name?.firstLetter ?? roster.contactBareJid.firstLetter),
2024-09-19 16:50:48 +00:00
text: roster.contactBareJid,
controlType: .none
)
.onTapGesture {
startChat()
}
.swipeActions(edge: .trailing, allowsFullSwipe: false) {
Button {
router.showAlert(.confirmationDialog, title: L10n.Contacts.deleteContact, subtitle: L10n.Contacts.Delete.message) {
deleteConfirmation
}
} label: {
Label("", systemImage: "trash")
}
.tint(Color.red)
}
.contextMenu {
Button(L10n.Contacts.sendMessage, systemImage: "message") {
startChat()
}
Divider()
Button(L10n.Contacts.editContact) {
print("Edit contact")
}
Button(L10n.Contacts.selectContact) {
print("Select contact")
}
Divider()
Button(L10n.Contacts.deleteContact, systemImage: "trash", role: .destructive) {
router.showAlert(.confirmationDialog, title: L10n.Contacts.deleteContact, subtitle: L10n.Contacts.Delete.message) {
deleteConfirmation
}
}
}
}
@ViewBuilder private var deleteConfirmation: some View {
Button(role: .destructive) {
Task {
await deleteFromDevice()
}
} label: {
Text(L10n.Contacts.Delete.deleteFromDevice)
}
Button(role: .destructive) {
Task {
await deleteCompletely()
}
} label: {
Text(L10n.Contacts.Delete.deleteCompletely)
}
Button(role: .cancel) {} label: {
Text(L10n.Global.cancel)
}
}
private func deleteFromDevice() async {
router.showModal {
LoadingScreen()
}
defer {
router.dismissModal()
}
var roster = roster
try? await roster.setLocallyDeleted(true)
}
private func deleteCompletely() async {
router.showModal {
LoadingScreen()
}
defer {
router.dismissModal()
}
do {
try await clientsStore.deleteRoster(roster)
} catch {
router.showAlert(
.alert,
title: L10n.Global.Error.title,
subtitle: L10n.Contacts.Delete.error
) {
Button(L10n.Global.ok, role: .cancel) {}
}
}
}
private func startChat() {
Task {
router.showModal {
LoadingScreen()
}
defer {
router.dismissModal()
}
do {
2024-09-20 15:32:10 +00:00
let (messages, attachments, settings) = try await clientsStore.conversationStores(for: roster)
router.showScreen(.push) { _ in
2024-09-20 15:32:10 +00:00
ConversationScreen(messagesStore: messages, attachments: attachments, settings: settings)
.navigationBarHidden(true)
}
} catch {
router.showAlert(
.alert,
title: L10n.Global.Error.title,
subtitle: L10n.Conversation.startError
) {
Button(L10n.Global.ok, role: .cancel) {}
}
}
}
}
}