This commit is contained in:
fmodf 2024-08-12 00:30:01 +02:00
parent eddec7412c
commit 882501782e
3 changed files with 55 additions and 46 deletions

View file

@ -16,27 +16,11 @@ enum ClientState: Equatable {
final class Client: ObservableObject {
@Published private(set) var state: ClientState = .enabled(.disconnected)
@Published private(set) var credentials: Credentials
var rosters: [Roster] {
get async {
// Fetching only non-locally-deleted rosters and only for active credentials
if credentials.isActive {
let creds = credentials
let rosters = try? await Database.shared.dbQueue.read { db in
try Roster
.filter(Column("bareJid") == creds.bareJid)
.filter(Column("locallyDeleted") == false)
.fetchAll(db)
}
return rosters ?? []
} else {
return []
}
}
}
@Published private(set) var rosters: [Roster] = []
private var connection: XMPPClient
private var connectionCancellable: AnyCancellable?
private var rostersCancellable: AnyCancellable?
private var rosterManager = ClientMartinRosterManager()
@ -51,6 +35,18 @@ final class Client: ObservableObject {
self.state = .disabled
return
}
rostersCancellable = ValueObservation
.tracking { db in
try Roster
.filter(Column("bareJid") == self.credentials.bareJid)
.filter(Column("locallyDeleted") == false)
.fetchAll(db)
}
.publisher(in: Database.shared.dbQueue)
.catch { _ in Just([]) }
.sink { rosters in
self.rosters = rosters
}
switch state {
case .connected:
self.state = .enabled(.connected)

View file

@ -8,20 +8,21 @@ final class ClientsStore: ObservableObject {
@Published private(set) var ready = false
@Published private(set) var clients: [Client] = []
@Published private(set) var actualRosters: [Roster] = []
private let credentialsObservation = ValueObservation.tracking(Credentials.fetchAll)
private var credentialsCancellable: AnyCancellable?
private var rostersCancellable: AnyCancellable?
init() {
Task {
do {
for try await creds in credentialsObservation.values(in: Database.shared.dbQueue) {
processCredentials(creds)
if !ready {
ready = true
}
}
} catch {}
}
credentialsCancellable = ValueObservation
.tracking { db in
try Credentials.fetchAll(db)
}
.publisher(in: Database.shared.dbQueue)
.catch { _ in Just([]) }
.sink { [weak self] creds in
self?.processCredentials(creds)
}
}
private func processCredentials(_ credentials: [Credentials]) {
@ -37,6 +38,12 @@ final class ClientsStore: ObservableObject {
var updatedClients = clients.filter { credentialsJids.contains($0.credentials.bareJid) }
updatedClients.append(contentsOf: newClients)
clients = updatedClients
if !ready {
ready = true
}
resubscribeRosters()
}
private func client(for credentials: Credentials) -> Client? {
@ -69,16 +76,6 @@ extension ClientsStore {
}
extension ClientsStore {
var actualRosters: [Roster] {
get async {
var allRosters: [Roster] = []
for client in clients {
allRosters.append(contentsOf: await client.rosters)
}
return allRosters
}
}
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()
@ -93,4 +90,22 @@ extension ClientsStore {
}
try await client.addRoster(contactJID, name: name, groups: groups)
}
private func resubscribeRosters() {
let clientsJids = clients
.filter { $0.state != .disabled }
.map { $0.credentials.bareJid }
rostersCancellable = ValueObservation.tracking { db in
try Roster
.filter(clientsJids.contains(Column("bareJid")))
.filter(Column("locallyDeleted") == false)
.fetchAll(db)
}
.publisher(in: Database.shared.dbQueue)
.catch { _ in Just([]) }
.sink { [weak self] rosters in
self?.actualRosters = rosters
}
}
}

View file

@ -4,8 +4,6 @@ struct ContactsScreen: View {
@Environment(\.router) var router
@EnvironmentObject var clientsStore: ClientsStore
@State private var rosters: [Roster] = []
var body: some View {
ZStack {
// Background color
@ -28,9 +26,9 @@ struct ContactsScreen: View {
)
// Contacts list
if !rosters.isEmpty {
if !clientsStore.actualRosters.isEmpty {
List {
ForEach(rosters) { roster in
ForEach(clientsStore.actualRosters) { roster in
ContactsScreenRow(
roster: roster
)
@ -43,9 +41,9 @@ struct ContactsScreen: View {
}
}
}
.task {
rosters = await clientsStore.actualRosters
}
// .task {
// rosters = await clientsStore.actualRosters
// }
// .alert(isPresented: $isErrorAlertPresented) {
// Alert(
// title: Text(L10n.Global.Error.title),