169 lines
5.8 KiB
Swift
169 lines
5.8 KiB
Swift
import SwiftUI
|
|
|
|
struct ContactsScreen: View {
|
|
@EnvironmentObject var store: AppStore
|
|
|
|
@State private var addPanelPresented = false
|
|
@State private var isErrorAlertPresented = false
|
|
@State private var errorAlertMessage = ""
|
|
@State private var isShowingLoader = false
|
|
|
|
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: {
|
|
addPanelPresented = true
|
|
}
|
|
)
|
|
)
|
|
|
|
// Contacts list
|
|
let rosters = store.state.rostersState.rosters.filter { !$0.locallyDeleted }
|
|
if !rosters.isEmpty {
|
|
List {
|
|
ForEach(rosters) { roster in
|
|
ContactsScreenRow(
|
|
roster: roster,
|
|
isErrorAlertPresented: $isErrorAlertPresented,
|
|
errorAlertMessage: $errorAlertMessage,
|
|
isShowingLoader: $isShowingLoader
|
|
)
|
|
}
|
|
}
|
|
.listStyle(.plain)
|
|
.background(Color.Material.Background.light)
|
|
} else {
|
|
Spacer()
|
|
}
|
|
|
|
// Tab bar
|
|
SharedTabBar()
|
|
}
|
|
}
|
|
.loadingIndicator(isShowingLoader)
|
|
.fullScreenCover(isPresented: $addPanelPresented) {
|
|
AddContactOrChannelScreen(isPresented: $addPanelPresented)
|
|
}
|
|
.alert(isPresented: $isErrorAlertPresented) {
|
|
Alert(
|
|
title: Text(L10n.Global.Error.title),
|
|
message: Text(errorAlertMessage),
|
|
dismissButton: .default(Text(L10n.Global.ok))
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
private struct ContactsScreenRow: View {
|
|
@EnvironmentObject var store: AppStore
|
|
|
|
var roster: Roster
|
|
@State private var isShowingMenu = false
|
|
@State private var isDeleteAlertPresented = false
|
|
|
|
@Binding var isErrorAlertPresented: Bool
|
|
@Binding var errorAlertMessage: String
|
|
@Binding var isShowingLoader: Bool
|
|
|
|
var body: some View {
|
|
VStack(spacing: 0) {
|
|
HStack(spacing: 8) {
|
|
ZStack {
|
|
Circle()
|
|
.frame(width: 44, height: 44)
|
|
.foregroundColor(.red)
|
|
Text(roster.name?.firstLetter ?? roster.contactBareJid.firstLetter)
|
|
.foregroundColor(.white)
|
|
.font(.body1)
|
|
}
|
|
Text(roster.contactBareJid)
|
|
.foregroundColor(Color.Material.Text.main)
|
|
.font(.body2)
|
|
Spacer()
|
|
}
|
|
.padding(.horizontal, 16)
|
|
.padding(.vertical, 4)
|
|
Rectangle()
|
|
.frame(maxWidth: .infinity)
|
|
.frame(height: 1)
|
|
.foregroundColor(.Material.Background.dark)
|
|
}
|
|
.sharedListRow()
|
|
.onTapGesture {
|
|
store.dispatch(.chatsAction(.startChat(accountJid: roster.bareJid, participantJid: roster.contactBareJid)))
|
|
}
|
|
.onLongPressGesture {
|
|
isShowingMenu.toggle()
|
|
}
|
|
.swipeActions(edge: .trailing, allowsFullSwipe: false) {
|
|
Button {
|
|
isDeleteAlertPresented = true
|
|
} label: {
|
|
Label(L10n.Contacts.sendMessage, systemImage: "trash")
|
|
}
|
|
.tint(Color.red)
|
|
}
|
|
.contextMenu {
|
|
Button(L10n.Contacts.sendMessage, systemImage: "message") {
|
|
store.dispatch(.chatsAction(.startChat(accountJid: roster.bareJid, participantJid: roster.contactBareJid)))
|
|
}
|
|
Divider()
|
|
|
|
Button(L10n.Contacts.editContact) {
|
|
print("Edit contact")
|
|
}
|
|
|
|
Button(L10n.Contacts.selectContact) {
|
|
print("Select contact")
|
|
}
|
|
|
|
Divider()
|
|
Button(L10n.Contacts.deleteContact, systemImage: "trash", role: .destructive) {
|
|
isDeleteAlertPresented = true
|
|
}
|
|
}
|
|
.actionSheet(isPresented: $isDeleteAlertPresented) {
|
|
ActionSheet(
|
|
title: Text(L10n.Contacts.Delete.title),
|
|
message: Text(L10n.Contacts.Delete.message),
|
|
buttons: [
|
|
.destructive(Text(L10n.Contacts.Delete.deleteFromDevice)) {
|
|
store.dispatch(.rostersAction(.markRosterAsLocallyDeleted(ownerJID: roster.bareJid, contactJID: roster.contactBareJid)))
|
|
},
|
|
.destructive(Text(L10n.Contacts.Delete.deleteCompletely)) {
|
|
isShowingLoader = true
|
|
store.dispatch(.rostersAction(.deleteRoster(ownerJID: roster.bareJid, contactJID: roster.contactBareJid)))
|
|
},
|
|
.cancel(Text(L10n.Global.cancel))
|
|
]
|
|
)
|
|
}
|
|
.onChange(of: store.state.rostersState.rosters) { _ in
|
|
endOfDeleting()
|
|
}
|
|
.onChange(of: store.state.rostersState.deleteRosterError) { _ in
|
|
endOfDeleting()
|
|
}
|
|
}
|
|
|
|
private func endOfDeleting() {
|
|
if isShowingLoader {
|
|
isShowingLoader = false
|
|
if let error = store.state.rostersState.deleteRosterError {
|
|
errorAlertMessage = error
|
|
isErrorAlertPresented = true
|
|
}
|
|
}
|
|
}
|
|
}
|