From fbc14986239f8df8de689578c4eb2117c0155d08 Mon Sep 17 00:00:00 2001 From: Finn Behrens Date: Tue, 15 Jun 2021 18:18:15 +0200 Subject: [PATCH] fix pagination ciclyc dependency --- Nio.xcodeproj/project.pbxproj | 6 ++ Nio/Conversations/RoomView.swift | 49 ++++++++---- Nio/NewConversation/NewConversationView.swift | 6 +- Nio/Shared Views/ReverseList.swift | 2 +- NioKit/Extensions/MX+Identifiable.swift | 2 +- NioKit/Extensions/MXAutoDiscovery+Async.swift | 8 +- NioKit/Extensions/MXClient+Publisher.swift | 10 +-- .../Extensions/MXCredentials+Keychain.swift | 12 +-- NioKit/Extensions/MXEvent+Extensions.swift | 14 ++-- NioKit/Extensions/MXEventTimeLine+Async.swift | 27 +++++++ NioKit/Extensions/MXRestClient+Async.swift | 14 ++-- NioKit/Extensions/MXRoom+Async.swift | 16 +++- NioKit/Extensions/UXKit.swift | 79 +++++++++---------- NioKit/Extensions/UserDefaults.swift | 15 ++-- NioKit/Models/NIORoom.swift | 56 +++++++++++++ NioKit/Session/AccountStore.swift | 49 ++++++------ 16 files changed, 238 insertions(+), 127 deletions(-) create mode 100644 NioKit/Extensions/MXEventTimeLine+Async.swift diff --git a/Nio.xcodeproj/project.pbxproj b/Nio.xcodeproj/project.pbxproj index e7fe73f3..5473490b 100644 --- a/Nio.xcodeproj/project.pbxproj +++ b/Nio.xcodeproj/project.pbxproj @@ -79,6 +79,8 @@ 9525D2EC267659A2004055B6 /* SettingsContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9525D2EB267659A2004055B6 /* SettingsContainerView.swift */; }; 9525D2ED267659BD004055B6 /* SettingsContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9525D2E62676594F004055B6 /* SettingsContainerView.swift */; }; 9525D2EE26765C8C004055B6 /* RecentRoomsContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39C932062384BB13004449E1 /* RecentRoomsContainerView.swift */; }; + 95CAC7B82678F64E001D71DC /* MXEventTimeLine+Async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95CAC7B72678F64E001D71DC /* MXEventTimeLine+Async.swift */; }; + 95CAC7B92678F64E001D71DC /* MXEventTimeLine+Async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95CAC7B72678F64E001D71DC /* MXEventTimeLine+Async.swift */; }; A51BF8CE254C2FE5000FB0A4 /* NioApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = A51BF8CD254C2FE5000FB0A4 /* NioApp.swift */; }; A51F762C25D6E9950061B4A4 /* MessageTextViewWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = A51F762B25D6E9950061B4A4 /* MessageTextViewWrapper.swift */; }; A58352A625A667AB00533363 /* MatrixSDK in Frameworks */ = {isa = PBXBuildFile; productRef = A58352A525A667AB00533363 /* MatrixSDK */; }; @@ -383,6 +385,7 @@ 9525D2E326765850004055B6 /* RoomView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomView.swift; sourceTree = ""; }; 9525D2E62676594F004055B6 /* SettingsContainerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsContainerView.swift; sourceTree = ""; }; 9525D2EB267659A2004055B6 /* SettingsContainerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsContainerView.swift; sourceTree = ""; }; + 95CAC7B72678F64E001D71DC /* MXEventTimeLine+Async.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MXEventTimeLine+Async.swift"; sourceTree = ""; }; A51BF8CD254C2FE5000FB0A4 /* NioApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NioApp.swift; sourceTree = ""; }; A51F762B25D6E9950061B4A4 /* MessageTextViewWrapper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageTextViewWrapper.swift; sourceTree = ""; }; CAAF5BF72478696F006FDC33 /* UITextViewWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UITextViewWrapper.swift; sourceTree = ""; }; @@ -864,6 +867,7 @@ 393411C823904428003B49B8 /* MXEvent+Extensions.swift */, 4BEB8C03250403D200E90699 /* UserDefaults.swift */, E897AA3325F2716F00D11427 /* UXKit.swift */, + 95CAC7B72678F64E001D71DC /* MXEventTimeLine+Async.swift */, ); path = Extensions; sourceTree = ""; @@ -1427,6 +1431,7 @@ E8B4726125F26D5A00ACEFCB /* AccountStore.swift in Sources */, E8B4725825F26D5A00ACEFCB /* CustomEvent.swift in Sources */, E8B4725F25F26D5A00ACEFCB /* Configuration.swift in Sources */, + 95CAC7B82678F64E001D71DC /* MXEventTimeLine+Async.swift in Sources */, E8B4725D25F26D5A00ACEFCB /* EventCollection.swift in Sources */, 9525D2D426763DD0004055B6 /* MXAutoDiscovery+Async.swift in Sources */, E8B4725E25F26D5A00ACEFCB /* MXEvent+Extensions.swift in Sources */, @@ -1516,6 +1521,7 @@ E897AA2325F2707C00D11427 /* Reaction.swift in Sources */, E897AA1925F2707C00D11427 /* EditEvent.swift in Sources */, E897AA1F25F2707C00D11427 /* MX+Identifiable.swift in Sources */, + 95CAC7B92678F64E001D71DC /* MXEventTimeLine+Async.swift in Sources */, E897AA1D25F2707C00D11427 /* MXCredentials+Keychain.swift in Sources */, 9525D2D326763DD0004055B6 /* MXAutoDiscovery+Async.swift in Sources */, E897AA2425F2707C00D11427 /* MXEvent+Extensions.swift in Sources */, diff --git a/Nio/Conversations/RoomView.swift b/Nio/Conversations/RoomView.swift index 851d4ea0..3c0ecc1b 100644 --- a/Nio/Conversations/RoomView.swift +++ b/Nio/Conversations/RoomView.swift @@ -1,6 +1,6 @@ -import SwiftUI import Combine import MatrixSDK +import SwiftUI import NioKit @@ -29,7 +29,7 @@ struct RoomView: View { @State private var shouldPaginate = false private var areOtherUsersTyping: Bool { - return !(room.room.typingUsers?.filter { $0 != userId }.isEmpty ?? true) + !(room.room.typingUsers?.filter { $0 != userId }.isEmpty ?? true) } var body: some View { @@ -41,18 +41,19 @@ struct RoomView: View { showSender: !self.isDirect, edits: self.events.relatedEvents(of: event).filter { $0.isEdit() }, contextMenuModel: EventContextMenuModel( - event: event, - userId: self.userId, - onReact: { self.onReact(event.eventId) }, - onReply: { }, - onEdit: { self.edit(event: event) }, - onRedact: { - if event.sentState == MXEventSentStateFailed { - room.removeOutgoingMessage(event) - } else { - self.eventToRedact = event.eventId - } - })) + event: event, + userId: self.userId, + onReact: { self.onReact(event.eventId) }, + onReply: {}, + onEdit: { self.edit(event: event) }, + onRedact: { + if event.sentState == MXEventSentStateFailed { + room.removeOutgoingMessage(event) + } else { + self.eventToRedact = event.eventId + } + } + )) .padding(.horizontal) } @@ -72,12 +73,26 @@ struct RoomView: View { onCancel: cancelEdit, onCommit: send ) - .padding(.horizontal) - .padding(.bottom, 10) + .padding(.horizontal) + .padding(.bottom, 10) } .onChange(of: shouldPaginate) { newValue in if newValue, let topEvent = events.renderableEvents.first { - store.paginate(room: self.room, event: topEvent) + asyncDetached { + print("paginating") + await room.paginate(topEvent) + } + } + } + .onAppear { + asyncDetached { + if let topEvent = events.renderableEvents.first { + // await room.paginate(topEvent) + await room.createPagination() + } else { + print("did not find topEvent") + await room.createPagination() + } } } .alert(item: $eventToRedact) { eventId in diff --git a/Nio/NewConversation/NewConversationView.swift b/Nio/NewConversation/NewConversationView.swift index 780117db..45c408df 100644 --- a/Nio/NewConversation/NewConversationView.swift +++ b/Nio/NewConversation/NewConversationView.swift @@ -70,7 +70,7 @@ private struct NewConversationView: View { // Seems to be a bug in Xcode, currently needs to be asnyc, to be able to await actor Button(action: { async { - createRoom + await createRoom() } }) { Text(verbatim: L10n.NewConversation.createRoom) @@ -151,7 +151,7 @@ private struct NewConversationView: View { } } - @MainActor private func createRoom() { + private func createRoom() async { isWaiting = true let parameters = MXRoomCreationParameters() @@ -173,7 +173,7 @@ private struct NewConversationView: View { } } - store?.session?.createRoom(parameters: parameters) { response in + await store?.session?.createRoom(parameters: parameters) { response in switch response { case .success(let room): createdRoomId = room.id diff --git a/Nio/Shared Views/ReverseList.swift b/Nio/Shared Views/ReverseList.swift index 503a3eaf..4547ed63 100644 --- a/Nio/Shared Views/ReverseList.swift +++ b/Nio/Shared Views/ReverseList.swift @@ -43,7 +43,7 @@ struct ReverseList: View where Element: Identifiable, Content: } .frame(height: 30) // FIXME: Frame height shouldn't be hard-coded .onPreferenceChange(IsVisibleKey.self) { - hasReachedTop = $0 + if $0 != hasReachedTop { hasReachedTop = $0 } } } .scaleEffect(x: -1.0, y: 1.0) diff --git a/NioKit/Extensions/MX+Identifiable.swift b/NioKit/Extensions/MX+Identifiable.swift index 1fce4e0e..fa7a97ba 100644 --- a/NioKit/Extensions/MX+Identifiable.swift +++ b/NioKit/Extensions/MX+Identifiable.swift @@ -1,5 +1,5 @@ -import SwiftUI import MatrixSDK +import SwiftUI extension MXPublicRoom: Identifiable {} extension MXRoom: Identifiable {} diff --git a/NioKit/Extensions/MXAutoDiscovery+Async.swift b/NioKit/Extensions/MXAutoDiscovery+Async.swift index 9129eca5..8850a922 100644 --- a/NioKit/Extensions/MXAutoDiscovery+Async.swift +++ b/NioKit/Extensions/MXAutoDiscovery+Async.swift @@ -8,10 +8,10 @@ import Foundation import MatrixSDK -extension MXAutoDiscovery { - public func findClientConfig() async throws -> MXDiscoveredClientConfig { - return try await withCheckedThrowingContinuation {continuation in - self.findClientConfig({ continuation.resume(returning: $0)}, failure: {continuation.resume(throwing: $0)}) +public extension MXAutoDiscovery { + func findClientConfig() async throws -> MXDiscoveredClientConfig { + try await withCheckedThrowingContinuation { continuation in + self.findClientConfig({ continuation.resume(returning: $0) }, failure: { continuation.resume(throwing: $0) }) } } } diff --git a/NioKit/Extensions/MXClient+Publisher.swift b/NioKit/Extensions/MXClient+Publisher.swift index 1b5ab5c9..e5c7e2c6 100644 --- a/NioKit/Extensions/MXClient+Publisher.swift +++ b/NioKit/Extensions/MXClient+Publisher.swift @@ -1,15 +1,15 @@ -import Foundation import Combine +import Foundation import MatrixSDK -extension MXRestClient { - public func nio_publicRooms(onServer: String? = nil, limit: UInt? = nil) -> AnyPublisher { +public extension MXRestClient { + func nio_publicRooms(onServer: String? = nil, limit: UInt? = nil) -> AnyPublisher { Future { promise in self.publicRooms(onServer: onServer, limit: limit) { response in switch response { - case .failure(let error): + case let .failure(error): promise(.failure(error)) - case .success(let publicRoomsResponse): + case let .success(publicRoomsResponse): promise(.success(publicRoomsResponse)) @unknown default: fatalError("Unexpected Matrix response: \(response)") diff --git a/NioKit/Extensions/MXCredentials+Keychain.swift b/NioKit/Extensions/MXCredentials+Keychain.swift index 9bdbc0b3..e2dbf727 100644 --- a/NioKit/Extensions/MXCredentials+Keychain.swift +++ b/NioKit/Extensions/MXCredentials+Keychain.swift @@ -1,10 +1,10 @@ -import MatrixSDK import KeychainAccess +import MatrixSDK -extension MXCredentials { - public func save(to keychain: Keychain) { +public extension MXCredentials { + func save(to keychain: Keychain) { guard - let homeserver = self.homeServer, + let homeserver = homeServer, let userId = self.userId, let accessToken = self.accessToken, let deviceId = self.deviceId @@ -17,14 +17,14 @@ extension MXCredentials { keychain["deviceId"] = deviceId } - public func clear(from keychain: Keychain) { + func clear(from keychain: Keychain) { keychain["homeserver"] = nil keychain["userId"] = nil keychain["accessToken"] = nil keychain["deviceId"] = nil } - public static func from(_ keychain: Keychain) -> MXCredentials? { + static func from(_ keychain: Keychain) -> MXCredentials? { guard let homeserver = keychain["homeserver"], let userId = keychain["userId"], diff --git a/NioKit/Extensions/MXEvent+Extensions.swift b/NioKit/Extensions/MXEvent+Extensions.swift index fc34cc89..fbe79476 100644 --- a/NioKit/Extensions/MXEvent+Extensions.swift +++ b/NioKit/Extensions/MXEvent+Extensions.swift @@ -1,20 +1,20 @@ import Foundation import MatrixSDK -extension MXEvent { - public var timestamp: Date { - Date(timeIntervalSince1970: TimeInterval(self.originServerTs / 1000)) +public extension MXEvent { + var timestamp: Date { + Date(timeIntervalSince1970: TimeInterval(originServerTs / 1000)) } - public func content(valueFor key: String) -> T? { - if let value = self.content?[key] as? T { + func content(valueFor key: String) -> T? { + if let value = content?[key] as? T { return value } return nil } - public func prevContent(valueFor key: String) -> T? { - if let value = self.unsignedData?.prevContent?[key] as? T { + func prevContent(valueFor key: String) -> T? { + if let value = unsignedData?.prevContent?[key] as? T { return value } return nil diff --git a/NioKit/Extensions/MXEventTimeLine+Async.swift b/NioKit/Extensions/MXEventTimeLine+Async.swift new file mode 100644 index 00000000..a124e864 --- /dev/null +++ b/NioKit/Extensions/MXEventTimeLine+Async.swift @@ -0,0 +1,27 @@ +// +// MXEventTimeLine+Async.swift +// Nio +// +// Created by Finn Behrens on 15.06.21. +// Copyright © 2021 Kilian Koeltzsch. All rights reserved. +// + +import Foundation +import MatrixSDK + +extension MXEventTimeline { + func paginate(_ numItems: UInt, direction: MXTimelineDirection = .backwards, onlyFromStore: Bool = false) async throws { + return try await withCheckedThrowingContinuation {continuation in + self.paginate(numItems, direction: direction, onlyFromStore: onlyFromStore, completion: {resp in + switch resp { + case .success(_): + continuation.resume() + case .failure(let e): + continuation.resume(throwing: e) + @unknown default: + continuation.resume(throwing: NioUnknownContinuationSwitchError(value: resp)) + } + }) + } + } +} diff --git a/NioKit/Extensions/MXRestClient+Async.swift b/NioKit/Extensions/MXRestClient+Async.swift index c14d8679..fda623da 100644 --- a/NioKit/Extensions/MXRestClient+Async.swift +++ b/NioKit/Extensions/MXRestClient+Async.swift @@ -10,12 +10,12 @@ import MatrixSDK extension MXRestClient { func login(type loginType: MatrixSDK.MXLoginFlowType = .password, username: String, password: String) async throws -> MXCredentials { - return try await withCheckedThrowingContinuation {continuation in - self.login(type: loginType, username: username, password: password, completion: {resp in + try await withCheckedThrowingContinuation { continuation in + self.login(type: loginType, username: username, password: password, completion: { resp in switch resp { - case .success(let v): + case let .success(v): continuation.resume(returning: v) - case .failure(let e): + case let .failure(e): continuation.resume(throwing: e) @unknown default: continuation.resume(throwing: NioUnknownContinuationSwitchError(value: resp)) @@ -23,10 +23,10 @@ extension MXRestClient { }) } } - + func wellKnown() async throws -> MXWellKnown { - return try await withCheckedThrowingContinuation {continuation in - self.wellKnow({continuation.resume(returning: $0!)}, failure: {continuation.resume(throwing: $0!)}) + try await withCheckedThrowingContinuation { continuation in + self.wellKnow({ continuation.resume(returning: $0!) }, failure: { continuation.resume(throwing: $0!) }) } } } diff --git a/NioKit/Extensions/MXRoom+Async.swift b/NioKit/Extensions/MXRoom+Async.swift index 89bff57b..1f1732e5 100644 --- a/NioKit/Extensions/MXRoom+Async.swift +++ b/NioKit/Extensions/MXRoom+Async.swift @@ -10,12 +10,12 @@ import MatrixSDK extension MXRoom { func members() async throws -> MXRoomMembers? { - return try await withCheckedThrowingContinuation {continuation in - self.members(completion: {resp in + try await withCheckedThrowingContinuation { continuation in + self.members(completion: { resp in switch resp { - case .success(let v): + case let .success(v): continuation.resume(returning: v) - case .failure(let e): + case let .failure(e): continuation.resume(throwing: e) @unknown default: continuation.resume(throwing: NioUnknownContinuationSwitchError(value: resp)) @@ -23,4 +23,12 @@ extension MXRoom { }) } } + + var liveTimeline: MXEventTimeline { + get async { + await withCheckedContinuation { continuation in + self.liveTimeline { continuation.resume(returning: $0!) } + } + } + } } diff --git a/NioKit/Extensions/UXKit.swift b/NioKit/Extensions/UXKit.swift index dcf0d98b..95bb7035 100644 --- a/NioKit/Extensions/UXKit.swift +++ b/NioKit/Extensions/UXKit.swift @@ -9,67 +9,64 @@ #if os(macOS) import AppKit - public typealias UXColor = NSColor - public typealias UXImage = NSImage + public typealias UXColor = NSColor + public typealias UXImage = NSImage public typealias UXEdgeInsets = NSEdgeInsets - public typealias UXFont = NSFont + public typealias UXFont = NSFont public enum UXFakeTraitCollection { case current } public extension NSColor { - @inlinable - func resolvedColor(with fakeTraitCollection: UXFakeTraitCollection) - -> UXColor + func resolvedColor(with _: UXFakeTraitCollection) + -> UXColor { - return self + self } } - #if canImport(SwiftUI) - import SwiftUI - - public enum UXFakeDisplayMode { - case inline, automatic, large - } - public enum UXFakeAutocapitalizationMode { - case none - } + #if canImport(SwiftUI) + import SwiftUI - @available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *) - public extension View { - - @inlinable - func navigationBarTitle( - _ title: S, displayMode: UXFakeDisplayMode = .inline - ) -> some View - { - self.navigationTitle(title) + public enum UXFakeDisplayMode { + case inline, automatic, large } - - @inlinable - func autocapitalization(_ mode: UXFakeAutocapitalizationMode) -> Self { - return self + + public enum UXFakeAutocapitalizationMode { + case none } - } - #endif + + @available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *) + public extension View { + @inlinable + func navigationBarTitle( + _ title: S, displayMode _: UXFakeDisplayMode = .inline + ) -> some View { + navigationTitle(title) + } + + @inlinable + func autocapitalization(_: UXFakeAutocapitalizationMode) -> Self { + self + } + } + #endif #elseif canImport(UIKit) import UIKit - public typealias UXColor = UIColor - public typealias UXImage = UIImage + public typealias UXColor = UIColor + public typealias UXImage = UIImage public typealias UXEdgeInsets = UIEdgeInsets - public typealias UXFont = UIFont + public typealias UXFont = UIFont - #if canImport(SwiftUI) - import SwiftUI - - @available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *) - public extension View { - } - #endif + #if canImport(SwiftUI) + import SwiftUI + + @available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *) + public extension View {} + #endif #else #error("GNUstep not yet supported, sorry!") #endif diff --git a/NioKit/Extensions/UserDefaults.swift b/NioKit/Extensions/UserDefaults.swift index d4c689ae..6d19b469 100644 --- a/NioKit/Extensions/UserDefaults.swift +++ b/NioKit/Extensions/UserDefaults.swift @@ -15,14 +15,15 @@ public extension UserDefaults { } return group }() - #if os(macOS) - private static let teamIdentifierPrefix = Bundle.main - .object(forInfoDictionaryKey: "TeamIdentifierPrefix") as? String ?? "" - private static let suiteName = teamIdentifierPrefix + appGroup - #else // iOS - private static let suiteName = "group." + appGroup - #endif + #if os(macOS) + private static let teamIdentifierPrefix = Bundle.main + .object(forInfoDictionaryKey: "TeamIdentifierPrefix") as? String ?? "" + + private static let suiteName = teamIdentifierPrefix + appGroup + #else // iOS + private static let suiteName = "group." + appGroup + #endif static let group = UserDefaults(suiteName: suiteName)! } diff --git a/NioKit/Models/NIORoom.swift b/NioKit/Models/NIORoom.swift index 3c299481..43d0734e 100644 --- a/NioKit/Models/NIORoom.swift +++ b/NioKit/Models/NIORoom.swift @@ -3,6 +3,8 @@ import Combine import MatrixSDK +import os + public struct RoomItem: Codable, Hashable { public static func == (lhs: RoomItem, rhs: RoomItem) -> Bool { return lhs.displayName == rhs.displayName && @@ -22,6 +24,8 @@ public struct RoomItem: Codable, Hashable { @MainActor public class NIORoom: ObservableObject { + static let logger = Logger(subsystem: "chat.nio", category: "ROOM") + public let room: MXRoom @Published @@ -172,6 +176,58 @@ public class NIORoom: ObservableObject { objectWillChange.send() // room.outgoingMessages() will change room.removeOutgoingMessage(event.eventId) } + + //private var lastPaginatedEvent: MXEvent? + private var timeline: MXEventTimeline? + + public func paginate(_ event: MXEvent, direction: MXTimelineDirection = .backwards, numItems: UInt = 40) async { + /*guard event != lastPaginatedEvent else { + return + }*/ + + if timeline == nil { + Self.logger.debug("creating timeline for room '\(self.displayName)' with event '\(event.eventId)'") + //lastPaginatedEvent = event + timeline = room.timeline(onEvent: event.eventId) + let _ = timeline?.listenToEvents { + event, direction, roomState in + if direction == .backwards { + // eventCache is published, so no objectWillChanges.send here + self.add(event: event, direction: direction, roomState: roomState) + } + } + timeline?.resetPagination() + } + + if timeline?.canPaginate(direction) ?? false { + do { + try await timeline?.paginate(numItems, direction: direction, onlyFromStore: false) + } catch { + Self.logger.warning("could not paginate: \(error.localizedDescription)") + } + } else { + Self.logger.debug("cannot paginate: \(self.displayName)") + } + } + + public func createPagination() async { + guard timeline == nil else { + return + } + Self.logger.debug("Bootstraping pagination") + + timeline = await room.liveTimeline + timeline?.resetPagination() + if timeline?.canPaginate(.backwards) ?? false { + do { + try await timeline?.paginate(40, direction: .backwards) + } catch { + Self.logger.warning("could not bootstrap pagination: \(error.localizedDescription)") + } + } else { + Self.logger.warning("could not bootstrap pagination") + } + } } extension NIORoom: Identifiable { diff --git a/NioKit/Session/AccountStore.swift b/NioKit/Session/AccountStore.swift index 781fd4e9..49e6b905 100644 --- a/NioKit/Session/AccountStore.swift +++ b/NioKit/Session/AccountStore.swift @@ -1,7 +1,7 @@ -import Foundation import Combine -import MatrixSDK +import Foundation import KeychainAccess +import MatrixSDK public enum LoginState { case loggedOut @@ -20,7 +20,8 @@ public class AccountStore: ObservableObject { let keychain = Keychain( service: "chat.nio.credentials", - accessGroup: ((Bundle.main.infoDictionary?["DevelopmentTeam"] as? String) ?? "") + ".nio.keychain") + accessGroup: ((Bundle.main.infoDictionary?["DevelopmentTeam"] as? String) ?? "") + ".nio.keychain" + ) public init() { if CommandLine.arguments.contains("-clear-stored-credentials") { @@ -35,7 +36,7 @@ public class AccountStore: ObservableObject { return } self.credentials = credentials - self.loginState = .authenticating + loginState = .authenticating async { do { self.loginState = try await self.sync() @@ -56,35 +57,35 @@ public class AccountStore: ObservableObject { @Published public var loginState: LoginState = .loggedOut public func login(username: String, password: String, homeserver: URL) async { - self.loginState = .authenticating + loginState = .authenticating - self.client = MXRestClient(homeServer: homeserver, unrecognizedCertificateHandler: nil) - self.client?.acceptableContentTypes = ["text/plain", "text/html", "application/json", "application/octet-stream", "any"] + client = MXRestClient(homeServer: homeserver, unrecognizedCertificateHandler: nil) + client?.acceptableContentTypes = ["text/plain", "text/html", "application/json", "application/octet-stream", "any"] do { - let credentials = try await self.client?.login(username: username, password: password) + let credentials = try await client?.login(username: username, password: password) guard let credentials = credentials else { - self.loginState = .failure(AccountStoreError.noCredentials) + loginState = .failure(AccountStoreError.noCredentials) return } self.credentials = credentials - credentials.save(to: self.keychain) - self.loginState = try await self.sync() - self.session?.crypto.warnOnUnknowDevices = false + credentials.save(to: keychain) + loginState = try await sync() + session?.crypto.warnOnUnknowDevices = false } catch { - self.loginState = .failure(error) + loginState = .failure(error) } } public func logout() async { - self.credentials?.clear(from: keychain) + credentials?.clear(from: keychain) do { - try await self.session?.logout() - self.loginState = .loggedOut + try await session?.logout() + loginState = .loggedOut } catch { // Close the session even if the logout request failed - self.loginState = .loggedOut + loginState = .loggedOut } } @@ -100,18 +101,17 @@ public class AccountStore: ObservableObject { } } - private func sync() async throws -> LoginState { guard let credentials = self.credentials else { throw AccountStoreError.noCredentials } - self.client = MXRestClient(credentials: credentials, unrecognizedCertificateHandler: nil) - self.session = MXSession(matrixRestClient: self.client!) - self.fileStore = MXFileStore() + client = MXRestClient(credentials: credentials, unrecognizedCertificateHandler: nil) + session = MXSession(matrixRestClient: client!) + fileStore = MXFileStore() - try await self.session!.setStore(fileStore!) - try await self.session?.start() + try await session!.setStore(fileStore!) + try await session?.start() return .loggedIn(userId: credentials.userId!) } @@ -121,7 +121,7 @@ public class AccountStore: ObservableObject { public func startListeningForRoomEvents() { // roomState is nil for presence events, just for future reference - listenReference = self.session?.listenToEvents { event, direction, roomState in + listenReference = session?.listenToEvents { event, direction, roomState in let affectedRooms = self.rooms.filter { $0.summary.roomId == event.roomId } for room in affectedRooms { room.add(event: event, direction: direction, roomState: roomState as? MXRoomState) @@ -161,6 +161,7 @@ public class AccountStore: ObservableObject { var listenReferenceRoom: Any? + @available(*, deprecated, message: "Prefer paginating on the room instead") public func paginate(room: NIORoom, event: MXEvent) { let timeline = room.room.timeline(onEvent: event.eventId) listenReferenceRoom = timeline?.listenToEvents { event, direction, roomState in