mv-experiment #1
|
@ -76,21 +76,6 @@ extension ClientsStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
extension ClientsStore {
|
extension ClientsStore {
|
||||||
func addRoster(_ credentials: Credentials, contactJID: String, name: String?, groups: [String]) async throws {
|
|
||||||
// check that roster exist in db as locally deleted and undelete it
|
|
||||||
let deletedLocally = try await Roster.fetchDeletedLocally()
|
|
||||||
if var roster = deletedLocally.first(where: { $0.contactBareJid == contactJID }) {
|
|
||||||
try await roster.setLocallyDeleted(false)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// add new roster
|
|
||||||
guard let client = client(for: credentials) else {
|
|
||||||
throw ClientStoreError.clientNotFound
|
|
||||||
}
|
|
||||||
try await client.addRoster(contactJID, name: name, groups: groups)
|
|
||||||
}
|
|
||||||
|
|
||||||
private func resubscribeRosters() {
|
private func resubscribeRosters() {
|
||||||
let clientsJids = clients
|
let clientsJids = clients
|
||||||
.filter { $0.state != .disabled }
|
.filter { $0.state != .disabled }
|
||||||
|
@ -108,4 +93,26 @@ extension ClientsStore {
|
||||||
self?.actualRosters = rosters
|
self?.actualRosters = rosters
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func addRoster(_ credentials: Credentials, contactJID: String, name: String?, groups: [String]) async throws {
|
||||||
|
// check that roster exist in db as locally deleted and undelete it
|
||||||
|
let deletedLocally = try await Roster.fetchDeletedLocally()
|
||||||
|
if var roster = deletedLocally.first(where: { $0.contactBareJid == contactJID }) {
|
||||||
|
try await roster.setLocallyDeleted(false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// add new roster
|
||||||
|
guard let client = client(for: credentials) else {
|
||||||
|
throw ClientStoreError.clientNotFound
|
||||||
|
}
|
||||||
|
try await client.addRoster(contactJID, name: name, groups: groups)
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteRoster(_ roster: Roster) async throws {
|
||||||
|
guard let client = clients.first(where: { $0.credentials.bareJid == roster.bareJid }) else {
|
||||||
|
throw ClientStoreError.clientNotFound
|
||||||
|
}
|
||||||
|
try await client.deleteRoster(roster)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,14 @@
|
||||||
"Contacts.Add.title" = "Add Contact";
|
"Contacts.Add.title" = "Add Contact";
|
||||||
"Contacts.Add.explanation" = "Contact or group/channel name are usually JID in format name@domain.ltd (like email)";
|
"Contacts.Add.explanation" = "Contact or group/channel name are usually JID in format name@domain.ltd (like email)";
|
||||||
"Contacts.Add.serverError" = "Contact adding dailed. Server returned error";
|
"Contacts.Add.serverError" = "Contact adding dailed. Server returned error";
|
||||||
|
"Contacts.deleteContact" = "Delete contact";
|
||||||
|
"Contacts.Delete.deleteFromDevice" = "Delete from device";
|
||||||
|
"Contacts.Delete.deleteCompletely" = "Delete completely";
|
||||||
|
"Contacts.sendMessage" = "Send message";
|
||||||
|
"Contacts.editContact" = "Edit contact";
|
||||||
|
"Contacts.selectContact" = "Select contact";
|
||||||
|
"Contacts.Delete.message" = "You can delete contact from this device (contact will be available on other devices), or delete it completely";
|
||||||
|
"Contacts.Delete.error" = "Contact not deleted. Server returns error.";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -39,27 +47,6 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: Onboar screen
|
|
||||||
//"Login.title" = "Let\'s go!";
|
|
||||||
//"Login.subtitle" = "Enter your JID, it should looks like email address";
|
|
||||||
//"Login.Hint.jid" = "user@domain.im";
|
|
||||||
//"Login.Hint.password" = "password";
|
|
||||||
//"Login.btn" = "Continue";
|
|
||||||
//"Login.Error.wrongPassword" = "Wrong password or JID";
|
|
||||||
//"Login.Error.noServer" = "Server not exists";
|
|
||||||
//"Login.Error.serverError" = "Server error. Check internet connection";
|
|
||||||
|
|
||||||
// MARK: Contacts screen
|
|
||||||
//"Contacts.sendMessage" = "Send message";
|
|
||||||
//"Contacts.editContact" = "Edit contact";
|
|
||||||
//"Contacts.selectContact" = "Select contact";
|
|
||||||
//"Contacts.deleteContact" = "Delete contact";
|
|
||||||
//"Contacts.Delete.title" = "Delete contact";
|
|
||||||
//"Contacts.Delete.message" = "You can delete contact from this device (contact will be available on other devices), or delete it completely";
|
|
||||||
//"Contacts.Delete.deleteFromDevice" = "Delete from device";
|
|
||||||
//"Contacts.Delete.deleteCompletely" = "Delete completely";
|
|
||||||
//"Contacts.Delete.error" = "Contact not deleted. Server returns error.";
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: Chats screen
|
// MARK: Chats screen
|
||||||
//"Chats.title" = "Chats";
|
//"Chats.title" = "Chats";
|
||||||
|
@ -72,21 +59,7 @@
|
||||||
//"Chats.Create.Main.createPrivateGroup" = "Create private group";
|
//"Chats.Create.Main.createPrivateGroup" = "Create private group";
|
||||||
//"Chats.Create.Main.findGroup" = "Find public group";
|
//"Chats.Create.Main.findGroup" = "Find public group";
|
||||||
|
|
||||||
// MARK: Accounts add screen
|
|
||||||
//"Accounts.Add.or" = "or";
|
|
||||||
//"Accounts.Add.Exist.title" = "Add existing\naccount";
|
|
||||||
//"Accounts.Add.Exist.Prompt.jid" = "Enter your XMPP ID";
|
|
||||||
//"Accounts.Add.Exist.Prompt.password" = "Enter password";
|
|
||||||
//"Accounts.Add.Exist.Hint.jid" = "user@domain.im";
|
|
||||||
//"Accounts.Add.Exist.Hint.password" = "password";
|
|
||||||
//"Accounts.Add.Exist.Btn.link" = "create a new one";
|
|
||||||
//"Accounts.Add.Exist.Btn.main" = "Continue";
|
|
||||||
//"Accounts.Add.Exist.loginError" = "Wrong login or password";
|
|
||||||
|
|
||||||
// MARK: Server connecting indicator
|
|
||||||
//"ServerConnectingIndicator.State.connecting" = "Connecting to server";
|
|
||||||
//"ServerConnectingIndicator.State.connected" = "Connected";
|
|
||||||
//"ServerConnectingIndicator.State.error" = "Server unreachable. Check internet connection and server name";
|
|
||||||
|
|
||||||
// MARK: Attachments
|
// MARK: Attachments
|
||||||
//"Attachment.Prompt.main" = "Select attachment";
|
//"Attachment.Prompt.main" = "Select attachment";
|
||||||
|
|
|
@ -41,49 +41,14 @@ struct ContactsScreen: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// .task {
|
|
||||||
// rosters = await clientsStore.actualRosters
|
|
||||||
// }
|
|
||||||
// .alert(isPresented: $isErrorAlertPresented) {
|
|
||||||
// Alert(
|
|
||||||
// title: Text(L10n.Global.Error.title),
|
|
||||||
// message: Text(errorAlertMessage),
|
|
||||||
// dismissButton: .default(Text(L10n.Global.ok))
|
|
||||||
// )
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// private func fetchRosters() async {
|
|
||||||
// let jids = clientsStore.clients
|
|
||||||
// .filter { $0.state != .disabled }
|
|
||||||
// .map { $0.credentials.bareJid }
|
|
||||||
//
|
|
||||||
// do {
|
|
||||||
// try await withThrowingTaskGroup(of: [Roster].self) { group in
|
|
||||||
// for jid in jids {
|
|
||||||
// group.addTask {
|
|
||||||
// try await Roster.fetchAll(for: jid)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// var allRosters: [Roster] = []
|
|
||||||
// for try await rosters in group {
|
|
||||||
// allRosters.append(contentsOf: rosters)
|
|
||||||
// }
|
|
||||||
// self.rosters = allRosters.sorted { $0.contactBareJid < $1.contactBareJid }
|
|
||||||
// }
|
|
||||||
// } catch {}
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private struct ContactsScreenRow: View {
|
private struct ContactsScreenRow: View {
|
||||||
|
@Environment(\.router) var router
|
||||||
|
@EnvironmentObject var clientsStore: ClientsStore
|
||||||
|
|
||||||
var roster: Roster
|
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 {
|
var body: some View {
|
||||||
SharedListRow(
|
SharedListRow(
|
||||||
|
@ -93,67 +58,93 @@ private struct ContactsScreenRow: View {
|
||||||
.onTapGesture {
|
.onTapGesture {
|
||||||
// store.dispatch(.chatsAction(.startChat(accountJid: roster.bareJid, participantJid: roster.contactBareJid)))
|
// store.dispatch(.chatsAction(.startChat(accountJid: roster.bareJid, participantJid: roster.contactBareJid)))
|
||||||
}
|
}
|
||||||
// .onLongPressGesture {
|
.swipeActions(edge: .trailing, allowsFullSwipe: false) {
|
||||||
// isShowingMenu.toggle()
|
Button {
|
||||||
// }
|
router.showAlert(.confirmationDialog, title: L10n.Contacts.deleteContact, subtitle: L10n.Contacts.Delete.message) {
|
||||||
// .swipeActions(edge: .trailing, allowsFullSwipe: false) {
|
deleteConfirmation
|
||||||
// Button {
|
}
|
||||||
// isDeleteAlertPresented = true
|
} label: {
|
||||||
// } label: {
|
Label("", systemImage: "trash")
|
||||||
// Label(L10n.Contacts.sendMessage, systemImage: "trash")
|
}
|
||||||
// }
|
.tint(Color.red)
|
||||||
// .tint(Color.red)
|
}
|
||||||
// }
|
.contextMenu {
|
||||||
// .contextMenu {
|
Button(L10n.Contacts.sendMessage, systemImage: "message") {
|
||||||
// Button(L10n.Contacts.sendMessage, systemImage: "message") {
|
|
||||||
// store.dispatch(.chatsAction(.startChat(accountJid: roster.bareJid, participantJid: roster.contactBareJid)))
|
// store.dispatch(.chatsAction(.startChat(accountJid: roster.bareJid, participantJid: roster.contactBareJid)))
|
||||||
// }
|
}
|
||||||
// Divider()
|
Divider()
|
||||||
//
|
|
||||||
// Button(L10n.Contacts.editContact) {
|
Button(L10n.Contacts.editContact) {
|
||||||
// print("Edit contact")
|
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() {
|
Button(L10n.Contacts.selectContact) {
|
||||||
// if isShowingLoader {
|
print("Select contact")
|
||||||
// isShowingLoader = false
|
}
|
||||||
// if let error = store.state.rostersState.deleteRosterError {
|
|
||||||
// errorAlertMessage = error
|
Divider()
|
||||||
// isErrorAlertPresented = true
|
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) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,9 +27,7 @@ struct MainTabScreen: View {
|
||||||
// ConversationsScreen()
|
// ConversationsScreen()
|
||||||
|
|
||||||
case .contacts:
|
case .contacts:
|
||||||
RouterView { _ in
|
|
||||||
ContactsScreen()
|
ContactsScreen()
|
||||||
}
|
|
||||||
|
|
||||||
case .settings:
|
case .settings:
|
||||||
Color.green
|
Color.green
|
||||||
|
|
Loading…
Reference in a new issue