mv-experiment #1
|
@ -42,11 +42,11 @@ final class Client: ObservableObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func addRoster(_ roster: Roster) async throws {
|
func addRoster(_ jid: String, name: String?, groups: [String]) async throws {
|
||||||
_ = try await connection.module(.roster).addItem(
|
_ = try await connection.module(.roster).addItem(
|
||||||
jid: JID(roster.contactBareJid),
|
jid: JID(jid),
|
||||||
name: roster.name,
|
name: name,
|
||||||
groups: roster.data.groups
|
groups: groups
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,8 +26,7 @@ struct Credentials: DBStorable, Hashable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// extension Account: UniversalInputSelectionElement {
|
extension Credentials: UniversalInputSelectionElement {
|
||||||
// var text: String? { bareJid }
|
var text: String? { bareJid }
|
||||||
// var icon: Image? { nil }
|
var icon: Image? { nil }
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
|
|
|
@ -62,10 +62,11 @@ extension Roster: Equatable {
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Roster {
|
extension Roster {
|
||||||
static func fetchAll(for jid: String) async throws -> [Roster] {
|
mutating func setLocallyDeleted(_ value: Bool) async throws {
|
||||||
let rosters = try await Database.shared.dbQueue.read { db in
|
locallyDeleted = value
|
||||||
try Roster.filter(Column("bareJid") == jid).fetchAll(db)
|
let copy = self
|
||||||
}
|
try? await Database.shared.dbQueue.write { db in
|
||||||
return rosters
|
try copy.save(db)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import GRDB
|
||||||
@MainActor
|
@MainActor
|
||||||
final class RostersStore: ObservableObject {
|
final class RostersStore: ObservableObject {
|
||||||
@Published private(set) var rosters: [Roster] = []
|
@Published private(set) var rosters: [Roster] = []
|
||||||
|
@Published private(set) var locallyDeletedRosters: [Roster] = []
|
||||||
|
|
||||||
private var cancellable: AnyCancellable?
|
private var cancellable: AnyCancellable?
|
||||||
|
|
||||||
|
@ -19,6 +20,7 @@ final class RostersStore: ObservableObject {
|
||||||
.catch { _ in Just([]) }
|
.catch { _ in Just([]) }
|
||||||
|
|
||||||
cancellable = clientsPublisher
|
cancellable = clientsPublisher
|
||||||
|
.map { $0.filter { $0.state != .disabled } } // look rosters only for enabled clients
|
||||||
.flatMap { clients in
|
.flatMap { clients in
|
||||||
Publishers.MergeMany(clients.map { $0.$state })
|
Publishers.MergeMany(clients.map { $0.$state })
|
||||||
.prepend(clients.map { $0.state })
|
.prepend(clients.map { $0.state })
|
||||||
|
@ -31,7 +33,80 @@ final class RostersStore: ObservableObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
private func handleUpdates(clientStates: [ClientState], rosters: [Roster]) {
|
private func handleUpdates(clientStates: [ClientState], rosters: [Roster]) {
|
||||||
self.rosters = rosters
|
self.rosters = rosters.filter { !$0.locallyDeleted }
|
||||||
|
locallyDeletedRosters = rosters.filter { $0.locallyDeleted }
|
||||||
print("Client States: \(clientStates.count), Rosters: \(rosters.count)")
|
print("Client States: \(clientStates.count), Rosters: \(rosters.count)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension RostersStore {
|
||||||
|
enum RosterAddResult {
|
||||||
|
case success
|
||||||
|
case connectionError
|
||||||
|
case serverError
|
||||||
|
}
|
||||||
|
|
||||||
|
func addRoster(ownerJid: String, contactJID: String, name _: String?, groups _: [String]) async -> RosterAddResult {
|
||||||
|
// check if such roster was already exists or locally deleted
|
||||||
|
if var exists = rosters.first(where: { $0.bareJid == ownerJid && $0.contactBareJid == contactJID }), exists.locallyDeleted {
|
||||||
|
try? await exists.setLocallyDeleted(false)
|
||||||
|
return .success
|
||||||
|
}
|
||||||
|
|
||||||
|
// add new roster
|
||||||
|
// check that client is enabled and connected
|
||||||
|
guard let client = ClientsStore.shared.clients.first(where: { $0.credentials.bareJid == ownerJid }), client.state == .enabled(.connected) else {
|
||||||
|
return .connectionError
|
||||||
|
}
|
||||||
|
|
||||||
|
// add roster
|
||||||
|
do {
|
||||||
|
try await client.addRoster(contactJID, name: nil, groups: [])
|
||||||
|
return .success
|
||||||
|
} catch {
|
||||||
|
return .serverError
|
||||||
|
}
|
||||||
|
|
||||||
|
// guard let client = clientsStore.clients.first(where: { $0.credentials == ownerCredentials }), client.state == .enabled(.connected) else {
|
||||||
|
// router.showAlert(
|
||||||
|
// .alert,
|
||||||
|
// title: L10n.Global.Error.title,
|
||||||
|
// subtitle: L10n.Contacts.Add.connectionError
|
||||||
|
// ) {
|
||||||
|
// Button(L10n.Global.ok, role: .cancel) {}
|
||||||
|
// }
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// router.showModal {
|
||||||
|
// LoadingScreen()
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// do {
|
||||||
|
// try await client.addRoster(contactJID, name: nil, groups: [])
|
||||||
|
// } catch {
|
||||||
|
// router.showAlert(
|
||||||
|
// .alert,
|
||||||
|
// title: L10n.Global.Error.title,
|
||||||
|
// subtitle: L10n.Contacts.Add.serverError
|
||||||
|
// ) {
|
||||||
|
// Button(L10n.Global.ok, role: .cancel) {}
|
||||||
|
// }
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// router.dismissModal()
|
||||||
|
// router.dismissScreen()
|
||||||
|
|
||||||
|
// client.addRoster(jid: )
|
||||||
|
|
||||||
|
// guard let ownerAccount else { return }
|
||||||
|
// if let exists = store.state.rostersState.rosters.first(where: { $0.bareJid == ownerAccount.bareJid && $0.contactBareJid == contactJID }), exists.locallyDeleted {
|
||||||
|
// store.dispatch(.rostersAction(.unmarkRosterAsLocallyDeleted(ownerJID: ownerAccount.bareJid, contactJID: contactJID)))
|
||||||
|
// isPresented = false
|
||||||
|
// } else {
|
||||||
|
// isShowingLoader = true
|
||||||
|
// store.dispatch(.rostersAction(.addRoster(ownerJID: ownerAccount.bareJid, contactJID: contactJID, name: nil, groups: [])))
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -24,8 +24,15 @@
|
||||||
"Tabs.Name.conversations" = "Chats";
|
"Tabs.Name.conversations" = "Chats";
|
||||||
"Tabs.Name.settings" = "Settings";
|
"Tabs.Name.settings" = "Settings";
|
||||||
|
|
||||||
|
// MARK: Contacts screen
|
||||||
|
"Contacts.title" = "Contacts";
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: Add contact/channel screen
|
||||||
|
"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.serverError" = "Contact not added. Server returns error.";
|
||||||
|
"Contacts.Add.connectionError" = "You need to be connected to internet for add contact/channel";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -44,55 +51,51 @@
|
||||||
//"Login.Error.serverError" = "Server error. Check internet connection";
|
//"Login.Error.serverError" = "Server error. Check internet connection";
|
||||||
|
|
||||||
// MARK: Contacts screen
|
// MARK: Contacts screen
|
||||||
"Contacts.title" = "Contacts";
|
//"Contacts.sendMessage" = "Send message";
|
||||||
"Contacts.sendMessage" = "Send message";
|
//"Contacts.editContact" = "Edit contact";
|
||||||
"Contacts.editContact" = "Edit contact";
|
//"Contacts.selectContact" = "Select contact";
|
||||||
"Contacts.selectContact" = "Select contact";
|
//"Contacts.deleteContact" = "Delete contact";
|
||||||
"Contacts.deleteContact" = "Delete contact";
|
//"Contacts.Delete.title" = "Delete contact";
|
||||||
"Contacts.Add.title" = "Add Contact";
|
//"Contacts.Delete.message" = "You can delete contact from this device (contact will be available on other devices), or delete it completely";
|
||||||
"Contacts.Add.explanation" = "Contact or group/channel name are usually JID in format name@domain.ltd (like email)";
|
//"Contacts.Delete.deleteFromDevice" = "Delete from device";
|
||||||
"Contacts.Add.error" = "Contact not added. Server returns error.";
|
//"Contacts.Delete.deleteCompletely" = "Delete completely";
|
||||||
"Contacts.Delete.title" = "Delete contact";
|
//"Contacts.Delete.error" = "Contact not deleted. Server returns error.";
|
||||||
"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";
|
||||||
|
|
||||||
"Chat.title" = "Chat";
|
//"Chat.title" = "Chat";
|
||||||
"Chat.textfieldPrompt" = "Type a message";
|
//"Chat.textfieldPrompt" = "Type a message";
|
||||||
|
|
||||||
"Chats.Create.Main.title" = "Create";
|
//"Chats.Create.Main.title" = "Create";
|
||||||
"Chats.Create.Main.createGroup" = "Create public group";
|
//"Chats.Create.Main.createGroup" = "Create public group";
|
||||||
"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
|
// MARK: Accounts add screen
|
||||||
"Accounts.Add.or" = "or";
|
//"Accounts.Add.or" = "or";
|
||||||
"Accounts.Add.Exist.title" = "Add existing\naccount";
|
//"Accounts.Add.Exist.title" = "Add existing\naccount";
|
||||||
"Accounts.Add.Exist.Prompt.jid" = "Enter your XMPP ID";
|
//"Accounts.Add.Exist.Prompt.jid" = "Enter your XMPP ID";
|
||||||
"Accounts.Add.Exist.Prompt.password" = "Enter password";
|
//"Accounts.Add.Exist.Prompt.password" = "Enter password";
|
||||||
"Accounts.Add.Exist.Hint.jid" = "user@domain.im";
|
//"Accounts.Add.Exist.Hint.jid" = "user@domain.im";
|
||||||
"Accounts.Add.Exist.Hint.password" = "password";
|
//"Accounts.Add.Exist.Hint.password" = "password";
|
||||||
"Accounts.Add.Exist.Btn.link" = "create a new one";
|
//"Accounts.Add.Exist.Btn.link" = "create a new one";
|
||||||
"Accounts.Add.Exist.Btn.main" = "Continue";
|
//"Accounts.Add.Exist.Btn.main" = "Continue";
|
||||||
"Accounts.Add.Exist.loginError" = "Wrong login or password";
|
//"Accounts.Add.Exist.loginError" = "Wrong login or password";
|
||||||
|
|
||||||
// MARK: Server connecting indicator
|
// MARK: Server connecting indicator
|
||||||
"ServerConnectingIndicator.State.connecting" = "Connecting to server";
|
//"ServerConnectingIndicator.State.connecting" = "Connecting to server";
|
||||||
"ServerConnectingIndicator.State.connected" = "Connected";
|
//"ServerConnectingIndicator.State.connected" = "Connected";
|
||||||
"ServerConnectingIndicator.State.error" = "Server unreachable. Check internet connection and server name";
|
//"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";
|
||||||
"Attachment.Tab.media" = "Media";
|
//"Attachment.Tab.media" = "Media";
|
||||||
"Attachment.Tab.files" = "Files";
|
//"Attachment.Tab.files" = "Files";
|
||||||
"Attachment.Tab.location" = "Location";
|
//"Attachment.Tab.location" = "Location";
|
||||||
"Attachment.Tab.contacts" = "Contacts";
|
//"Attachment.Tab.contacts" = "Contacts";
|
||||||
"Attachment.Send.media" = "Send media";
|
//"Attachment.Send.media" = "Send media";
|
||||||
"Attachment.Send.location" = "Send location";
|
//"Attachment.Send.location" = "Send location";
|
||||||
"Attachment.Send.contact" = "Send contact";
|
//"Attachment.Send.contact" = "Send contact";
|
||||||
"Attachment.Downloading.retry" = "Retry";
|
//"Attachment.Downloading.retry" = "Retry";
|
||||||
|
|
|
@ -2,21 +2,18 @@ import SwiftUI
|
||||||
|
|
||||||
struct AddContactOrChannelScreen: View {
|
struct AddContactOrChannelScreen: View {
|
||||||
@Environment(\.router) var router
|
@Environment(\.router) var router
|
||||||
|
@EnvironmentObject var clientsStore: ClientsStore
|
||||||
|
@EnvironmentObject var rostersStore: RostersStore
|
||||||
|
|
||||||
// enum Field {
|
enum Field {
|
||||||
// case account
|
case account
|
||||||
// case contact
|
case contact
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// @FocusState private var focus: Field?
|
@FocusState private var focus: Field?
|
||||||
//
|
|
||||||
// @Binding var isPresented: Bool
|
@State private var ownerCredentials: Credentials?
|
||||||
// @State private var contactJID: String = ""
|
@State private var contactJID: String = ""
|
||||||
// // @State private var ownerAccount: Account?
|
|
||||||
//
|
|
||||||
// @State private var isShowingLoader = false
|
|
||||||
// @State private var isShowingAlert = false
|
|
||||||
// @State private var errorMsg = ""
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ZStack {
|
ZStack {
|
||||||
|
@ -43,107 +40,117 @@ struct AddContactOrChannelScreen: View {
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
// VStack(spacing: 16) {
|
// Content
|
||||||
// // Explanation text
|
VStack(spacing: 16) {
|
||||||
//
|
// Explanation text
|
||||||
// Text(L10n.Contacts.Add.explanation)
|
Text(L10n.Contacts.Add.explanation)
|
||||||
// .font(.body3)
|
.font(.body3)
|
||||||
// .foregroundColor(.Material.Shape.separator)
|
.foregroundColor(.Material.Shape.separator)
|
||||||
// .multilineTextAlignment(.center)
|
.multilineTextAlignment(.center)
|
||||||
// .padding(.top, 16)
|
.padding(.top, 16)
|
||||||
//
|
|
||||||
// // Account selector
|
// Account selector
|
||||||
// HStack(spacing: 0) {
|
HStack(spacing: 0) {
|
||||||
// Text("Use account:")
|
Text("Use account:")
|
||||||
// .font(.body2)
|
.font(.body2)
|
||||||
// .foregroundColor(.Material.Text.main)
|
.foregroundColor(.Material.Text.main)
|
||||||
// .frame(alignment: .leading)
|
.frame(alignment: .leading)
|
||||||
// Spacer()
|
Spacer()
|
||||||
// }
|
}
|
||||||
// // UniversalInputCollection.DropDownMenu(
|
UniversalInputCollection.DropDownMenu(
|
||||||
// // prompt: "Use account",
|
prompt: "Use account",
|
||||||
// // elements: store.state.accountsState.accounts,
|
elements: activeClientsCredentials,
|
||||||
// // selected: $ownerAccount,
|
selected: $ownerCredentials,
|
||||||
// // focus: $focus,
|
focus: $focus,
|
||||||
// // fieldType: .account
|
fieldType: .account
|
||||||
// // )
|
)
|
||||||
//
|
|
||||||
// // Contact text input
|
// Contact text input
|
||||||
// HStack(spacing: 0) {
|
HStack(spacing: 0) {
|
||||||
// Text("Contact JID:")
|
Text("Contact JID:")
|
||||||
// .font(.body2)
|
.font(.body2)
|
||||||
// .foregroundColor(.Material.Text.main)
|
.foregroundColor(.Material.Text.main)
|
||||||
// .frame(alignment: .leading)
|
.frame(alignment: .leading)
|
||||||
// Spacer()
|
Spacer()
|
||||||
// }
|
}
|
||||||
// UniversalInputCollection.TextField(
|
UniversalInputCollection.TextField(
|
||||||
// prompt: "Contact or channel JID",
|
prompt: "Contact or channel JID",
|
||||||
// text: $contactJID,
|
text: $contactJID,
|
||||||
// focus: $focus,
|
focus: $focus,
|
||||||
// fieldType: .contact,
|
fieldType: .contact,
|
||||||
// contentType: .emailAddress,
|
contentType: .emailAddress,
|
||||||
// keyboardType: .emailAddress,
|
keyboardType: .emailAddress,
|
||||||
// submitLabel: .done,
|
submitLabel: .done,
|
||||||
// action: {
|
action: {
|
||||||
// focus = .account
|
focus = .account
|
||||||
// }
|
}
|
||||||
// )
|
)
|
||||||
//
|
|
||||||
// // Save button
|
// Save button
|
||||||
// Button {
|
Button {
|
||||||
// navigation.flow = .main(.contacts(.list))
|
Task {
|
||||||
// } label: {
|
await save()
|
||||||
// Text(L10n.Global.save)
|
}
|
||||||
// }
|
} label: {
|
||||||
// .buttonStyle(PrimaryButtonStyle())
|
Text(L10n.Global.save)
|
||||||
// .disabled(!inputValid)
|
}
|
||||||
// .padding(.top)
|
.buttonStyle(PrimaryButtonStyle())
|
||||||
// Spacer()
|
.disabled(!inputValid)
|
||||||
// }
|
.padding(.top)
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
.padding(.horizontal, 32)
|
.padding(.horizontal, 32)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// .onAppear {
|
.onAppear {
|
||||||
// if let exists = store.state.accountsState.accounts.first, exists.isActive {
|
if let exists = activeClientsCredentials.first {
|
||||||
// ownerAccount = exists
|
ownerCredentials = exists
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// .loadingIndicator(isShowingLoader)
|
}
|
||||||
// .alert(isPresented: $isShowingAlert) {
|
|
||||||
// Alert(
|
private var activeClientsCredentials: [Credentials] {
|
||||||
// title: Text(L10n.Global.Error.title),
|
clientsStore.clients
|
||||||
// message: Text(errorMsg),
|
.filter { $0.state != .disabled }
|
||||||
// dismissButton: .default(Text(L10n.Global.ok))
|
.map { $0.credentials }
|
||||||
// )
|
|
||||||
// }
|
|
||||||
// .onChange(of: store.state.rostersState.newAddedRosterJid) { jid in
|
|
||||||
// if jid != nil, isShowingLoader {
|
|
||||||
// isShowingLoader = false
|
|
||||||
// isPresented = false
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// .onChange(of: store.state.rostersState.newAddedRosterError) { error in
|
|
||||||
// if let error = error, isShowingLoader {
|
|
||||||
// isShowingLoader = false
|
|
||||||
// errorMsg = error
|
|
||||||
// isShowingAlert = true
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private var inputValid: Bool {
|
private var inputValid: Bool {
|
||||||
true
|
ownerCredentials != nil && !contactJID.isEmpty && UniversalInputCollection.Validators.isEmail(contactJID)
|
||||||
// ownerAccount != nil && !contactJID.isEmpty && UniversalInputCollection.Validators.isEmail(contactJID)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// private func save() {
|
private func save() async {
|
||||||
// guard let ownerAccount else { return }
|
guard let ownerCredentials = ownerCredentials else { return }
|
||||||
// if let exists = store.state.rostersState.rosters.first(where: { $0.bareJid == ownerAccount.bareJid && $0.contactBareJid == contactJID }), exists.locallyDeleted {
|
|
||||||
// store.dispatch(.rostersAction(.unmarkRosterAsLocallyDeleted(ownerJID: ownerAccount.bareJid, contactJID: contactJID)))
|
router.showModal {
|
||||||
// isPresented = false
|
LoadingScreen()
|
||||||
// } else {
|
}
|
||||||
// isShowingLoader = true
|
|
||||||
// store.dispatch(.rostersAction(.addRoster(ownerJID: ownerAccount.bareJid, contactJID: contactJID, name: nil, groups: [])))
|
defer {
|
||||||
// }
|
router.dismissModal()
|
||||||
// }
|
}
|
||||||
|
|
||||||
|
let result = await rostersStore.addRoster(ownerJid: ownerCredentials.bareJid, contactJID: contactJID, name: nil, groups: [])
|
||||||
|
|
||||||
|
switch result {
|
||||||
|
case .success:
|
||||||
|
router.dismissScreen()
|
||||||
|
|
||||||
|
case .connectionError:
|
||||||
|
showErrorAlert(subtitle: L10n.Contacts.Add.connectionError)
|
||||||
|
|
||||||
|
case .serverError:
|
||||||
|
showErrorAlert(subtitle: L10n.Contacts.Add.serverError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func showErrorAlert(subtitle: String) {
|
||||||
|
router.showAlert(
|
||||||
|
.alert,
|
||||||
|
title: L10n.Global.Error.title,
|
||||||
|
subtitle: subtitle
|
||||||
|
) {
|
||||||
|
Button(L10n.Global.ok, role: .cancel) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,11 +5,6 @@ struct ContactsScreen: View {
|
||||||
@EnvironmentObject var clientsStore: ClientsStore
|
@EnvironmentObject var clientsStore: ClientsStore
|
||||||
@StateObject var rostersStore = RostersStore(clientsPublisher: ClientsStore.shared.$clients)
|
@StateObject var rostersStore = RostersStore(clientsPublisher: ClientsStore.shared.$clients)
|
||||||
|
|
||||||
// @State private var addPanelPresented = false
|
|
||||||
// @State private var isErrorAlertPresented = false
|
|
||||||
// @State private var errorAlertMessage = ""
|
|
||||||
// @State private var isShowingLoader = false
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ZStack {
|
ZStack {
|
||||||
// Background color
|
// Background color
|
||||||
|
@ -26,6 +21,7 @@ struct ContactsScreen: View {
|
||||||
action: {
|
action: {
|
||||||
router.showScreen(.fullScreenCover) { _ in
|
router.showScreen(.fullScreenCover) { _ in
|
||||||
AddContactOrChannelScreen()
|
AddContactOrChannelScreen()
|
||||||
|
.environmentObject(rostersStore)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -37,9 +33,6 @@ struct ContactsScreen: View {
|
||||||
ForEach(rostersStore.rosters) { roster in
|
ForEach(rostersStore.rosters) { roster in
|
||||||
ContactsScreenRow(
|
ContactsScreenRow(
|
||||||
roster: roster
|
roster: roster
|
||||||
// isErrorAlertPresented: $isErrorAlertPresented,
|
|
||||||
// errorAlertMessage: $errorAlertMessage,
|
|
||||||
// isShowingLoader: $isShowingLoader
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -103,9 +96,9 @@ private struct ContactsScreenRow: View {
|
||||||
iconType: .charCircle(roster.name?.firstLetter ?? roster.contactBareJid.firstLetter),
|
iconType: .charCircle(roster.name?.firstLetter ?? roster.contactBareJid.firstLetter),
|
||||||
text: roster.contactBareJid
|
text: roster.contactBareJid
|
||||||
)
|
)
|
||||||
// .onTapGesture {
|
.onTapGesture {
|
||||||
// store.dispatch(.chatsAction(.startChat(accountJid: roster.bareJid, participantJid: roster.contactBareJid)))
|
// store.dispatch(.chatsAction(.startChat(accountJid: roster.bareJid, participantJid: roster.contactBareJid)))
|
||||||
// }
|
}
|
||||||
// .onLongPressGesture {
|
// .onLongPressGesture {
|
||||||
// isShowingMenu.toggle()
|
// isShowingMenu.toggle()
|
||||||
// }
|
// }
|
||||||
|
|
Loading…
Reference in a new issue