mirror of
https://github.com/element-hq/element-x-ios.git
synced 2025-03-10 21:39:12 +00:00
vector-im/element-x-ios/issues/53 - Various tweaks following code review
This commit is contained in:
parent
73f507045b
commit
8fec97217f
@ -24,6 +24,7 @@
|
||||
1151DCC5EC2C6585826545EC /* UserIndicatorPresenterSpy.swift in Sources */ = {isa = PBXBuildFile; fileRef = B695D0D12086158BAD1D9859 /* UserIndicatorPresenterSpy.swift */; };
|
||||
1281625B25371BE53D36CB3A /* SeparatorRoomTimelineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1ED7E89865201EE7D53E6DA /* SeparatorRoomTimelineItem.swift */; };
|
||||
12F70C493FB69F4D7E9A37EA /* NavigationRouterStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = D29EBCBFEC6FD0941749404D /* NavigationRouterStore.swift */; };
|
||||
13C77FDF17C4C6627CFFC205 /* RoomTimelineItemFactoryProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7D25A35764C7B3DB78954AB5 /* RoomTimelineItemFactoryProtocol.swift */; };
|
||||
15D1F9C415D9C921643BA82E /* UserIndicatorRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61B73D5E21F524A9BE44448D /* UserIndicatorRequest.swift */; };
|
||||
17CC4FB64F3A670F43ECBE5F /* UITestsRootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CCA431E6EDD71F7067B5F9E7 /* UITestsRootView.swift */; };
|
||||
1999ECC6777752A2616775CF /* MemberDetailsProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A152791A2F56BD193BFE986 /* MemberDetailsProvider.swift */; };
|
||||
@ -35,6 +36,7 @@
|
||||
24906A1E82D0046655958536 /* MessageComposer.swift in Sources */ = {isa = PBXBuildFile; fileRef = E18CF12478983A5EB390FB26 /* MessageComposer.swift */; };
|
||||
277D2531C70F207A2F9F5906 /* KeychainControllerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 956BDA4AE16429AD015661A8 /* KeychainControllerProtocol.swift */; };
|
||||
2797C9D9BA642370F1C85D78 /* Untranslated.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = F75DF9500D69A3AAF8339E69 /* Untranslated.stringsdict */; };
|
||||
297CD0A27C87B0C50FF192EE /* RoomTimelineViewFactoryProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEE384418EB1FEDFA62C9CD0 /* RoomTimelineViewFactoryProtocol.swift */; };
|
||||
29AEE68A604940180AB9EBFF /* MockRoomSummary.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6BDAC8895AB2B77B47703AE /* MockRoomSummary.swift */; };
|
||||
2BA59D0AEFB4B82A2EC2A326 /* SwiftyBeaver in Frameworks */ = {isa = PBXBuildFile; productRef = A981A4CA233FB5C13B9CA690 /* SwiftyBeaver */; };
|
||||
2BAA5B222856068158D0B3C6 /* MatrixRustSDK in Frameworks */ = {isa = PBXBuildFile; productRef = B1E8B697DF78FE7F61FC6CA4 /* MatrixRustSDK */; };
|
||||
@ -110,6 +112,7 @@
|
||||
8810A2A30A68252EBB54EE05 /* HomeScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71BC7CA1BC1041E93077BBA1 /* HomeScreenModels.swift */; };
|
||||
8BBD3AA589DEE02A1B0923B2 /* NoticeRoomTimelineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F49CDE349C490D617332770 /* NoticeRoomTimelineItem.swift */; };
|
||||
8CC12086CBF91A7E10CDC205 /* HomeScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = D653265D006E708E4E51AD64 /* HomeScreenCoordinator.swift */; };
|
||||
8D9F646387DF656EF91EE4CB /* RoomMessageFactoryProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96F37AB24AF5A006521D38D1 /* RoomMessageFactoryProtocol.swift */; };
|
||||
90DF83A6A347F7EE7EDE89EE /* AttributedStringBuilderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF25E364AE85090A70AE4644 /* AttributedStringBuilderTests.swift */; };
|
||||
90EB25D13AE6EEF034BDE9D2 /* Assets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71D52BAA5BADB06E5E8C295D /* Assets.swift */; };
|
||||
93BA4A81B6D893271101F9F0 /* SwiftyBeaver in Frameworks */ = {isa = PBXBuildFile; productRef = FD43A50D9B75C9D6D30F006B /* SwiftyBeaver */; };
|
||||
@ -332,6 +335,7 @@
|
||||
7B04BD3874D736127A8156B8 /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
7BDF6A69C2BB99535193E554 /* si */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = si; path = si.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
7D0CBC76C80E04345E11F2DB /* Application.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Application.swift; sourceTree = "<group>"; };
|
||||
7D25A35764C7B3DB78954AB5 /* RoomTimelineItemFactoryProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineItemFactoryProtocol.swift; sourceTree = "<group>"; };
|
||||
7DA80FADE73CDF01E96F5B8E /* sq */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sq; path = sq.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
7DDBF99755A9008CF8C8499E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
|
||||
7E154FEA1E6FE964D3DF7859 /* fy */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fy; path = fy.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
@ -364,6 +368,7 @@
|
||||
956BDA4AE16429AD015661A8 /* KeychainControllerProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainControllerProtocol.swift; sourceTree = "<group>"; };
|
||||
95CC95CD75B688E946438165 /* Coordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Coordinator.swift; sourceTree = "<group>"; };
|
||||
967873B9E11828B67F64C89A /* UITestsAppCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UITestsAppCoordinator.swift; sourceTree = "<group>"; };
|
||||
96F37AB24AF5A006521D38D1 /* RoomMessageFactoryProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMessageFactoryProtocol.swift; sourceTree = "<group>"; };
|
||||
9772C1D2223108EB3131AEE4 /* zh-CN */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-CN"; path = "zh-CN.lproj/Localizable.strings"; sourceTree = "<group>"; };
|
||||
97F893DBB5F88D746C6DCDE5 /* ku */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ku; path = ku.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
997783054A2E95F9E624217E /* kaa */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = kaa; path = kaa.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
@ -461,6 +466,7 @@
|
||||
EBE5502760CF6CA2D7201883 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = ja; path = ja.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
||||
ED1D792EB82506A19A72C8DE /* RoomTimelineItemProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineItemProtocol.swift; sourceTree = "<group>"; };
|
||||
EE8BCD14EFED23459A43FDFF /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
EEE384418EB1FEDFA62C9CD0 /* RoomTimelineViewFactoryProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineViewFactoryProtocol.swift; sourceTree = "<group>"; };
|
||||
EFFA5FD06AAAC4AF544B594E /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
F012CB5EE3F2B67359F6CC52 /* target.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = target.yml; sourceTree = "<group>"; };
|
||||
F23BA6D4842D53C5AC9B7584 /* nn */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = nn; path = nn.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
||||
@ -620,6 +626,7 @@
|
||||
children = (
|
||||
3ACBDC1D28EFB7789EB467E0 /* MockRoomProxy.swift */,
|
||||
FA154570F693D93513E584C1 /* RoomMessageFactory.swift */,
|
||||
96F37AB24AF5A006521D38D1 /* RoomMessageFactoryProtocol.swift */,
|
||||
A65F140F9FE5E8D4DAEFF354 /* RoomProxy.swift */,
|
||||
47111410B6E659A697D472B5 /* RoomProxyProtocol.swift */,
|
||||
33996F58948B54839D653EC1 /* Members */,
|
||||
@ -849,8 +856,10 @@
|
||||
184CF8C196BE143AE226628D /* DecorationTimelineItemProtocol.swift */,
|
||||
218AB05B4E3889731959C5F1 /* EventBasedTimelineItemProtocol.swift */,
|
||||
105B2A8426404EF66F00CFDB /* RoomTimelineItemFactory.swift */,
|
||||
7D25A35764C7B3DB78954AB5 /* RoomTimelineItemFactoryProtocol.swift */,
|
||||
ED1D792EB82506A19A72C8DE /* RoomTimelineItemProtocol.swift */,
|
||||
3FEE631F3A4AFDC6652DD9DA /* RoomTimelineViewFactory.swift */,
|
||||
EEE384418EB1FEDFA62C9CD0 /* RoomTimelineViewFactoryProtocol.swift */,
|
||||
ACB6C5E4950B6C9842F35A38 /* RoomTimelineViewProvider.swift */,
|
||||
75D1D02F7F3AC1122FCFB4F3 /* Items */,
|
||||
);
|
||||
@ -1423,6 +1432,7 @@
|
||||
BF35062D06888FA80BD139FF /* Presentable.swift in Sources */,
|
||||
53B9C2240C2F5533246EE230 /* RectangleToastView.swift in Sources */,
|
||||
FE79E2BCCF69E8BF4D21E15A /* RoomMessageFactory.swift in Sources */,
|
||||
8D9F646387DF656EF91EE4CB /* RoomMessageFactoryProtocol.swift in Sources */,
|
||||
D0619D2E6B9C511190FBEB95 /* RoomMessageProtocol.swift in Sources */,
|
||||
4FC1EFE4968A259CBBACFAFB /* RoomProxy.swift in Sources */,
|
||||
FA9C427FFB11B1AA2DCC5602 /* RoomProxyProtocol.swift in Sources */,
|
||||
@ -1436,10 +1446,12 @@
|
||||
78B71D53C1FC55FB7A9B75F0 /* RoomTimelineController.swift in Sources */,
|
||||
9B8DE1D424E37581C7D99CCC /* RoomTimelineControllerProtocol.swift in Sources */,
|
||||
4E945AD6862C403F74E57755 /* RoomTimelineItemFactory.swift in Sources */,
|
||||
13C77FDF17C4C6627CFFC205 /* RoomTimelineItemFactoryProtocol.swift in Sources */,
|
||||
1AE4AEA0FA8DEF52671832E0 /* RoomTimelineItemProtocol.swift in Sources */,
|
||||
9BD3A773186291560DF92B62 /* RoomTimelineProvider.swift in Sources */,
|
||||
77D7DAA41AAB36800C1F2E2D /* RoomTimelineProviderProtocol.swift in Sources */,
|
||||
5D430CDE11EAC3E8E6B80A66 /* RoomTimelineViewFactory.swift in Sources */,
|
||||
297CD0A27C87B0C50FF192EE /* RoomTimelineViewFactoryProtocol.swift in Sources */,
|
||||
CF82143AA4A4F7BD11D22946 /* RoomTimelineViewProvider.swift in Sources */,
|
||||
7F19E97E7985F518C9018B83 /* RootRouter.swift in Sources */,
|
||||
2C0CE61E5DC177938618E0B1 /* RootRouterType.swift in Sources */,
|
||||
|
@ -99,14 +99,15 @@ class StateStoreViewModel<State: BindableState, ViewAction> {
|
||||
self.context = Context(initialViewState: initialViewState)
|
||||
self.context.viewActions.sink { [weak self] action in
|
||||
guard let self = self else { return }
|
||||
self.process(viewAction: action)
|
||||
|
||||
Task { await self.process(viewAction: action) }
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
}
|
||||
|
||||
/// Override to handles incoming `ViewAction`s from the `ViewModel`.
|
||||
/// - Parameter viewAction: The `ViewAction` to be processed in `ViewModel` implementation.
|
||||
func process(viewAction: ViewAction) {
|
||||
func process(viewAction: ViewAction) async {
|
||||
// Default implementation, -no-op
|
||||
}
|
||||
}
|
||||
|
@ -17,8 +17,7 @@
|
||||
import SwiftUI
|
||||
import Combine
|
||||
|
||||
typealias HomeScreenViewModelType = StateStoreViewModel<HomeScreenViewState,
|
||||
HomeScreenViewAction>
|
||||
typealias HomeScreenViewModelType = StateStoreViewModel<HomeScreenViewState, HomeScreenViewAction>
|
||||
|
||||
class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol {
|
||||
|
||||
@ -44,7 +43,7 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
|
||||
|
||||
// MARK: - Public
|
||||
|
||||
override func process(viewAction: HomeScreenViewAction) {
|
||||
override func process(viewAction: HomeScreenViewAction) async {
|
||||
switch viewAction {
|
||||
case .logout:
|
||||
completion?(.logout)
|
||||
@ -100,9 +99,7 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
|
||||
return
|
||||
}
|
||||
|
||||
Task {
|
||||
await roomSummary.loadDetails()
|
||||
}
|
||||
Task { await roomSummary.loadDetails() }
|
||||
}
|
||||
|
||||
private func buildOrUpdateRoomFromSummary(_ roomSummary: RoomSummaryProtocol) -> HomeScreenRoom {
|
||||
|
@ -16,8 +16,7 @@
|
||||
|
||||
import SwiftUI
|
||||
|
||||
typealias LoginScreenViewModelType = StateStoreViewModel<LoginScreenViewState,
|
||||
LoginScreenViewAction>
|
||||
typealias LoginScreenViewModelType = StateStoreViewModel<LoginScreenViewState, LoginScreenViewAction>
|
||||
|
||||
class LoginScreenViewModel: LoginScreenViewModelType, LoginScreenViewModelProtocol {
|
||||
|
||||
@ -38,7 +37,7 @@ class LoginScreenViewModel: LoginScreenViewModelType, LoginScreenViewModelProtoc
|
||||
|
||||
// MARK: - Public
|
||||
|
||||
override func process(viewAction: LoginScreenViewAction) {
|
||||
override func process(viewAction: LoginScreenViewAction) async {
|
||||
switch viewAction {
|
||||
case .login:
|
||||
completion?(.login((username: context.username, password: context.password)))
|
||||
|
@ -16,8 +16,7 @@
|
||||
|
||||
import SwiftUI
|
||||
|
||||
typealias RoomScreenViewModelType = StateStoreViewModel<RoomScreenViewState,
|
||||
RoomScreenViewAction>
|
||||
typealias RoomScreenViewModelType = StateStoreViewModel<RoomScreenViewState, RoomScreenViewAction>
|
||||
|
||||
class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol {
|
||||
|
||||
@ -26,12 +25,12 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
|
||||
}
|
||||
|
||||
private let timelineController: RoomTimelineControllerProtocol
|
||||
private let timelineViewFactory: RoomTimelineViewFactory
|
||||
private let timelineViewFactory: RoomTimelineViewFactoryProtocol
|
||||
|
||||
// MARK: - Setup
|
||||
|
||||
init(timelineController: RoomTimelineControllerProtocol,
|
||||
timelineViewFactory: RoomTimelineViewFactory,
|
||||
timelineViewFactory: RoomTimelineViewFactoryProtocol,
|
||||
roomName: String?) {
|
||||
self.timelineController = timelineController
|
||||
self.timelineViewFactory = timelineViewFactory
|
||||
@ -41,20 +40,20 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
|
||||
timelineController.callbacks
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] callback in
|
||||
guard let self = self else { return }
|
||||
|
||||
switch callback {
|
||||
case .updatedTimelineItems:
|
||||
self.buildTimelineViews()
|
||||
case .updatedTimelineItem(let itemId):
|
||||
guard let timelineItem = self.timelineController.timelineItems.first(where: { $0.id == itemId }),
|
||||
let viewIndex = self.state.items.firstIndex(where: { $0.id == itemId }) else {
|
||||
return
|
||||
}
|
||||
guard let self = self else { return }
|
||||
|
||||
self.state.items[viewIndex] = timelineViewFactory.buildTimelineViewFor(timelineItem)
|
||||
}
|
||||
}.store(in: &cancellables)
|
||||
switch callback {
|
||||
case .updatedTimelineItems:
|
||||
self.buildTimelineViews()
|
||||
case .updatedTimelineItem(let itemId):
|
||||
guard let timelineItem = self.timelineController.timelineItems.first(where: { $0.id == itemId }),
|
||||
let viewIndex = self.state.items.firstIndex(where: { $0.id == itemId }) else {
|
||||
return
|
||||
}
|
||||
|
||||
self.state.items[viewIndex] = timelineViewFactory.buildTimelineViewFor(timelineItem: timelineItem)
|
||||
}
|
||||
}.store(in: &cancellables)
|
||||
|
||||
state.contextMenuBuilder = buildContexMenuForItemId(_:)
|
||||
|
||||
@ -63,31 +62,29 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
|
||||
|
||||
// MARK: - Public
|
||||
|
||||
override func process(viewAction: RoomScreenViewAction) {
|
||||
Task {
|
||||
switch viewAction {
|
||||
case .loadPreviousPage:
|
||||
state.isBackPaginating = true
|
||||
|
||||
switch await timelineController.paginateBackwards(Constants.backPaginationPageSize) {
|
||||
default:
|
||||
state.isBackPaginating = false
|
||||
}
|
||||
|
||||
case .itemAppeared(let id):
|
||||
await timelineController.processItemAppearance(id)
|
||||
case .itemDisappeared(let id):
|
||||
await timelineController.processItemDisappearance(id)
|
||||
case .linkClicked(let url):
|
||||
MXLog.warning("Link clicked: \(url)")
|
||||
case .sendMessage:
|
||||
guard state.bindings.composerText.count > 0 else {
|
||||
return
|
||||
}
|
||||
|
||||
await timelineController.sendMessage(state.bindings.composerText)
|
||||
state.bindings.composerText = ""
|
||||
override func process(viewAction: RoomScreenViewAction) async {
|
||||
switch viewAction {
|
||||
case .loadPreviousPage:
|
||||
state.isBackPaginating = true
|
||||
|
||||
switch await timelineController.paginateBackwards(Constants.backPaginationPageSize) {
|
||||
default:
|
||||
state.isBackPaginating = false
|
||||
}
|
||||
|
||||
case .itemAppeared(let id):
|
||||
await timelineController.processItemAppearance(id)
|
||||
case .itemDisappeared(let id):
|
||||
await timelineController.processItemDisappearance(id)
|
||||
case .linkClicked(let url):
|
||||
MXLog.warning("Link clicked: \(url)")
|
||||
case .sendMessage:
|
||||
guard state.bindings.composerText.count > 0 else {
|
||||
return
|
||||
}
|
||||
|
||||
await timelineController.sendMessage(state.bindings.composerText)
|
||||
state.bindings.composerText = ""
|
||||
}
|
||||
}
|
||||
|
||||
@ -95,7 +92,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
|
||||
|
||||
private func buildTimelineViews() {
|
||||
let stateItems = timelineController.timelineItems.map { item in
|
||||
timelineViewFactory.buildTimelineViewFor(item)
|
||||
timelineViewFactory.buildTimelineViewFor(timelineItem: item)
|
||||
}
|
||||
|
||||
state.items = stateItems
|
||||
|
@ -60,9 +60,7 @@ class UserSession {
|
||||
Benchmark.startTrackingForIdentifier("ClientSync", message: "Started sync.")
|
||||
client.startSync()
|
||||
|
||||
Task {
|
||||
await updateRooms()
|
||||
}
|
||||
Task { await updateRooms() }
|
||||
}
|
||||
|
||||
var userIdentifier: String {
|
||||
@ -83,7 +81,8 @@ class UserSession {
|
||||
return .failure(.failedRetrievingDisplayName)
|
||||
}
|
||||
|
||||
}.value
|
||||
}
|
||||
.value
|
||||
}
|
||||
|
||||
func loadUserAvatarURL() async -> Result<String, UserSessionError> {
|
||||
@ -94,7 +93,8 @@ class UserSession {
|
||||
} catch {
|
||||
return .failure(.failedRetrievingDisplayName)
|
||||
}
|
||||
}.value
|
||||
}
|
||||
.value
|
||||
}
|
||||
|
||||
// MARK: ClientDelegate
|
||||
@ -116,7 +116,7 @@ class UserSession {
|
||||
Benchmark.endTrackingForIdentifier("ClientRooms", message: "Retrieved \(sdkRooms.count) rooms")
|
||||
|
||||
Benchmark.startTrackingForIdentifier("ProcessingRooms", message: "Started processing \(sdkRooms.count) rooms")
|
||||
let diff = sdkRooms.map({ $0.id()}).difference(from: currentRooms.map({ $0.id }))
|
||||
let diff = sdkRooms.map({ $0.id() }).difference(from: currentRooms.map(\.id))
|
||||
|
||||
for change in diff {
|
||||
switch change {
|
||||
@ -125,7 +125,7 @@ class UserSession {
|
||||
MXLog.error("Failed retrieving sdk room with id: \(id)")
|
||||
break
|
||||
}
|
||||
currentRooms.append(RoomProxy(room: sdkRoom, messageFactory: RoomMessageFactory()))
|
||||
currentRooms.append(RoomProxy(room: sdkRoom, roomMessageFactory: RoomMessageFactory()))
|
||||
case .remove(_, let id, _):
|
||||
currentRooms.removeAll { $0.id == id }
|
||||
}
|
||||
|
@ -73,6 +73,7 @@ struct MediaProvider: MediaProviderProtocol {
|
||||
MXLog.error("Failed retrieving image with error: \(error)")
|
||||
return .failure(.failedRetrievingImage)
|
||||
}
|
||||
}.value
|
||||
}
|
||||
.value
|
||||
}
|
||||
}
|
||||
|
@ -11,10 +11,6 @@ import UIKit
|
||||
|
||||
struct MockMediaProvider: MediaProviderProtocol {
|
||||
|
||||
func loadCurrentUserAvatar(_ completion: @escaping (Result<UIImage?, MediaProviderError>) -> Void) {
|
||||
|
||||
}
|
||||
|
||||
func imageFromSource(_ source: MediaSource?) -> UIImage? {
|
||||
return nil
|
||||
}
|
||||
@ -26,11 +22,7 @@ struct MockMediaProvider: MediaProviderProtocol {
|
||||
func imageFromURL(_ url: String?) -> UIImage? {
|
||||
return nil
|
||||
}
|
||||
|
||||
func loadImageFromURL(_ url: String, _ completion: @escaping (Result<UIImage, MediaProviderError>) -> Void) {
|
||||
|
||||
}
|
||||
|
||||
func loadImageFromURL(_ url: String) async -> Result<UIImage, MediaProviderError> {
|
||||
return .failure(.failedRetrievingImage)
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
import Foundation
|
||||
import MatrixRustSDK
|
||||
|
||||
struct RoomMessageFactory {
|
||||
struct RoomMessageFactory: RoomMessageFactoryProtocol {
|
||||
func buildRoomMessageFrom(_ message: AnyMessage) -> RoomMessageProtocol {
|
||||
if let textMessage = message.textMessage() {
|
||||
return TextRoomMessage(message: textMessage)
|
||||
|
@ -0,0 +1,14 @@
|
||||
//
|
||||
// RoomMessageFactoryProtocol.swift
|
||||
// ElementX
|
||||
//
|
||||
// Created by Stefan Ceriu on 26/05/2022.
|
||||
// Copyright © 2022 element.io. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import MatrixRustSDK
|
||||
|
||||
protocol RoomMessageFactoryProtocol {
|
||||
func buildRoomMessageFrom(_ message: AnyMessage) -> RoomMessageProtocol
|
||||
}
|
@ -27,7 +27,7 @@ private class WeakRoomProxyWrapper: RoomDelegate {
|
||||
|
||||
class RoomProxy: RoomProxyProtocol {
|
||||
private let room: Room
|
||||
private let messageFactory: RoomMessageFactory
|
||||
private let roomMessageFactory: RoomMessageFactoryProtocol
|
||||
|
||||
private var backwardStream: BackwardsStreamProtocol?
|
||||
|
||||
@ -37,9 +37,9 @@ class RoomProxy: RoomProxyProtocol {
|
||||
|
||||
private(set) var messages: [RoomMessageProtocol]
|
||||
|
||||
init(room: Room, messageFactory: RoomMessageFactory) {
|
||||
init(room: Room, roomMessageFactory: RoomMessageFactoryProtocol) {
|
||||
self.room = room
|
||||
self.messageFactory = messageFactory
|
||||
self.roomMessageFactory = roomMessageFactory
|
||||
messages = []
|
||||
|
||||
room.setDelegate(delegate: WeakRoomProxyWrapper(roomProxy: self))
|
||||
@ -91,7 +91,8 @@ class RoomProxy: RoomProxyProtocol {
|
||||
} catch {
|
||||
return .failure(.failedRetrievingMemberAvatarURL)
|
||||
}
|
||||
}.value
|
||||
}
|
||||
.value
|
||||
}
|
||||
|
||||
func loadDisplayNameForUserId(_ userId: String) async -> Result<String?, RoomProxyError> {
|
||||
@ -102,7 +103,8 @@ class RoomProxy: RoomProxyProtocol {
|
||||
} catch {
|
||||
return .failure(.failedRetrievingMemberDisplayName)
|
||||
}
|
||||
}.value
|
||||
}
|
||||
.value
|
||||
}
|
||||
|
||||
func loadDisplayName() async -> Result<String, RoomProxyError> {
|
||||
@ -119,7 +121,8 @@ class RoomProxy: RoomProxyProtocol {
|
||||
} catch {
|
||||
return .failure(.failedRetrievingDisplayName)
|
||||
}
|
||||
}.value
|
||||
}
|
||||
.value
|
||||
}
|
||||
|
||||
func paginateBackwards(count: UInt) async -> Result<Void, RoomProxyError> {
|
||||
@ -133,13 +136,14 @@ class RoomProxy: RoomProxyProtocol {
|
||||
Benchmark.endTrackingForIdentifier("BackPagination \(self.id)", message: "Finished backpaginating \(count) message(s) in room \(self.id)")
|
||||
|
||||
let messages = sdkMessages.map { message in
|
||||
self.messageFactory.buildRoomMessageFrom(message)
|
||||
self.roomMessageFactory.buildRoomMessageFrom(message)
|
||||
}.reversed()
|
||||
|
||||
self.messages.insert(contentsOf: messages, at: 0)
|
||||
|
||||
return .success(())
|
||||
}.value
|
||||
}
|
||||
.value
|
||||
}
|
||||
|
||||
func sendMessage(_ message: String) async -> Result<Void, RoomProxyError> {
|
||||
@ -153,13 +157,14 @@ class RoomProxy: RoomProxyProtocol {
|
||||
} catch {
|
||||
return .failure(.failedSendingMessage)
|
||||
}
|
||||
}.value
|
||||
}
|
||||
.value
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
fileprivate func appendMessage(_ message: AnyMessage) {
|
||||
let message = self.messageFactory.buildRoomMessageFrom(message)
|
||||
let message = roomMessageFactory.buildRoomMessageFrom(message)
|
||||
messages.append(message)
|
||||
callbacks.send(.updatedMessages)
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ struct EventBriefFactory: EventBriefFactoryProtocol {
|
||||
self.memberDetailProvider = memberDetailProvider
|
||||
}
|
||||
|
||||
func eventBriefForMessage(_ message: RoomMessageProtocol?) async -> EventBrief? {
|
||||
func buildEventBriefFor(message: RoomMessageProtocol?) async -> EventBrief? {
|
||||
guard let message = message else {
|
||||
return nil
|
||||
}
|
||||
@ -37,7 +37,7 @@ struct EventBriefFactory: EventBriefFactoryProtocol {
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func buildEventBrief(message: RoomMessageProtocol, htmlBody: String?) async -> EventBrief? {
|
||||
private func buildEventBrief(message: RoomMessageProtocol, htmlBody: String?) async -> EventBrief? {
|
||||
switch await memberDetailProvider.loadDisplayNameForUserId(message.sender) {
|
||||
case .success(let displayName):
|
||||
return EventBrief(eventId: message.id,
|
||||
|
@ -10,5 +10,5 @@ import Foundation
|
||||
|
||||
@MainActor
|
||||
protocol EventBriefFactoryProtocol {
|
||||
func eventBriefForMessage(_ message: RoomMessageProtocol?) async -> EventBrief?
|
||||
func buildEventBriefFor(message: RoomMessageProtocol?) async -> EventBrief?
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ struct MockRoomSummary: RoomSummaryProtocol {
|
||||
|
||||
var avatar: UIImage?
|
||||
|
||||
func loadDetails() {
|
||||
func loadDetails() async {
|
||||
|
||||
}
|
||||
|
||||
|
@ -48,19 +48,19 @@ class RoomSummary: RoomSummaryProtocol {
|
||||
|
||||
private(set) var displayName: String? {
|
||||
didSet {
|
||||
self.callbacks.send(.updatedData)
|
||||
callbacks.send(.updatedData)
|
||||
}
|
||||
}
|
||||
|
||||
private(set) var lastMessage: EventBrief? {
|
||||
didSet {
|
||||
self.callbacks.send(.updatedData)
|
||||
callbacks.send(.updatedData)
|
||||
}
|
||||
}
|
||||
|
||||
private(set) var avatar: UIImage? {
|
||||
didSet {
|
||||
self.callbacks.send(.updatedData)
|
||||
callbacks.send(.updatedData)
|
||||
}
|
||||
}
|
||||
|
||||
@ -72,7 +72,7 @@ class RoomSummary: RoomSummaryProtocol {
|
||||
self.eventBriefFactory = eventBriefFactory
|
||||
|
||||
Task {
|
||||
lastMessage = await eventBriefFactory.eventBriefForMessage(roomProxy.messages.last)
|
||||
lastMessage = await eventBriefFactory.buildEventBriefFor(message: roomProxy.messages.last)
|
||||
}
|
||||
|
||||
roomProxy.callbacks
|
||||
@ -85,7 +85,7 @@ class RoomSummary: RoomSummaryProtocol {
|
||||
switch callback {
|
||||
case .updatedMessages:
|
||||
Task {
|
||||
self.lastMessage = await eventBriefFactory.eventBriefForMessage(roomProxy.messages.last)
|
||||
self.lastMessage = await eventBriefFactory.buildEventBriefFor(message: roomProxy.messages.last)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -98,13 +98,13 @@ class RoomSummary: RoomSummaryProtocol {
|
||||
}
|
||||
|
||||
await withTaskGroup(of: Void.self) { group in
|
||||
group.addTask(priority: .medium) {
|
||||
group.addTask {
|
||||
await self.loadDisplayName()
|
||||
}
|
||||
group.addTask(priority: .medium) {
|
||||
group.addTask {
|
||||
await self.loadAvatar()
|
||||
}
|
||||
group.addTask(priority: .medium) {
|
||||
group.addTask {
|
||||
await self.loadLastMessage()
|
||||
}
|
||||
}
|
||||
@ -143,7 +143,7 @@ class RoomSummary: RoomSummaryProtocol {
|
||||
|
||||
switch await roomProxy.paginateBackwards(count: 1) {
|
||||
case .success:
|
||||
lastMessage = await eventBriefFactory.eventBriefForMessage(roomProxy.messages.last)
|
||||
lastMessage = await eventBriefFactory.buildEventBriefFor(message: roomProxy.messages.last)
|
||||
case .failure(let error):
|
||||
MXLog.error("Failed back paginating with error: \(error)")
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ import UIKit
|
||||
|
||||
class RoomTimelineController: RoomTimelineControllerProtocol {
|
||||
private let timelineProvider: RoomTimelineProviderProtocol
|
||||
private let timelineItemFactory: RoomTimelineItemFactory
|
||||
private let timelineItemFactory: RoomTimelineItemFactoryProtocol
|
||||
private let mediaProvider: MediaProviderProtocol
|
||||
private let memberDetailProvider: MemberDetailProviderProtocol
|
||||
|
||||
@ -23,7 +23,7 @@ class RoomTimelineController: RoomTimelineControllerProtocol {
|
||||
private(set) var timelineItems = [RoomTimelineItemProtocol]()
|
||||
|
||||
init(timelineProvider: RoomTimelineProviderProtocol,
|
||||
timelineItemFactory: RoomTimelineItemFactory,
|
||||
timelineItemFactory: RoomTimelineItemFactoryProtocol,
|
||||
mediaProvider: MediaProviderProtocol,
|
||||
memberDetailProvider: MemberDetailProviderProtocol) {
|
||||
self.timelineProvider = timelineProvider
|
||||
@ -35,13 +35,13 @@ class RoomTimelineController: RoomTimelineControllerProtocol {
|
||||
.callbacks
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] callback in
|
||||
guard let self = self else { return }
|
||||
|
||||
switch callback {
|
||||
case .updatedMessages:
|
||||
self.updateTimelineItems()
|
||||
}
|
||||
}.store(in: &cancellables)
|
||||
guard let self = self else { return }
|
||||
|
||||
switch callback {
|
||||
case .updatedMessages:
|
||||
self.updateTimelineItems()
|
||||
}
|
||||
}.store(in: &cancellables)
|
||||
|
||||
updateTimelineItems()
|
||||
|
||||
@ -59,7 +59,7 @@ class RoomTimelineController: RoomTimelineControllerProtocol {
|
||||
}
|
||||
|
||||
func processItemAppearance(_ itemId: String) async {
|
||||
guard let timelineItem = self.timelineItems.filter({ $0.id == itemId}).first else {
|
||||
guard let timelineItem = timelineItems.first(where: { $0.id == itemId }) else {
|
||||
return
|
||||
}
|
||||
|
||||
@ -98,8 +98,8 @@ class RoomTimelineController: RoomTimelineControllerProtocol {
|
||||
var newTimelineItems = [RoomTimelineItemProtocol]()
|
||||
|
||||
var previousMessage: RoomMessageProtocol?
|
||||
for message in self.timelineProvider.messages {
|
||||
let areMessagesFromTheSameDay = self.haveSameDay(lhs: previousMessage, rhs: message)
|
||||
for message in timelineProvider.messages {
|
||||
let areMessagesFromTheSameDay = haveSameDay(lhs: previousMessage, rhs: message)
|
||||
let shouldAddSectionHeader = !areMessagesFromTheSameDay
|
||||
|
||||
if shouldAddSectionHeader {
|
||||
@ -110,14 +110,14 @@ class RoomTimelineController: RoomTimelineControllerProtocol {
|
||||
let areMessagesFromTheSameSender = (previousMessage?.sender == message.sender)
|
||||
let shouldShowSenderDetails = !areMessagesFromTheSameSender || !areMessagesFromTheSameDay
|
||||
|
||||
newTimelineItems.append(timelineItemFactory.buildTimelineItemFor(message, showSenderDetails: shouldShowSenderDetails))
|
||||
newTimelineItems.append(timelineItemFactory.buildTimelineItemFor(message: message, showSenderDetails: shouldShowSenderDetails))
|
||||
|
||||
previousMessage = message
|
||||
}
|
||||
|
||||
self.timelineItems = newTimelineItems
|
||||
timelineItems = newTimelineItems
|
||||
|
||||
self.callbacks.send(.updatedTimelineItems)
|
||||
callbacks.send(.updatedTimelineItems)
|
||||
}
|
||||
|
||||
private func haveSameDay(lhs: RoomMessageProtocol?, rhs: RoomMessageProtocol?) -> Bool {
|
||||
|
@ -1,5 +1,5 @@
|
||||
//
|
||||
// TimelineItemFactory.swift
|
||||
// RoomTimelineItemFactory.swift
|
||||
// ElementX
|
||||
//
|
||||
// Created by Stefan Ceriu on 16/03/2022.
|
||||
@ -9,8 +9,7 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
@MainActor
|
||||
struct RoomTimelineItemFactory {
|
||||
struct RoomTimelineItemFactory: RoomTimelineItemFactoryProtocol {
|
||||
private let mediaProvider: MediaProviderProtocol
|
||||
private let memberDetailProvider: MemberDetailProviderProtocol
|
||||
private let attributedStringBuilder: AttributedStringBuilderProtocol
|
||||
@ -23,12 +22,12 @@ struct RoomTimelineItemFactory {
|
||||
self.attributedStringBuilder = attributedStringBuilder
|
||||
}
|
||||
|
||||
func buildTimelineItemFor(_ roomMessage: RoomMessageProtocol, showSenderDetails: Bool) -> RoomTimelineItemProtocol {
|
||||
let displayName = memberDetailProvider.displayNameForUserId(roomMessage.sender)
|
||||
let avatarURL = memberDetailProvider.avatarURLForUserId(roomMessage.sender)
|
||||
func buildTimelineItemFor(message: RoomMessageProtocol, showSenderDetails: Bool) -> RoomTimelineItemProtocol {
|
||||
let displayName = memberDetailProvider.displayNameForUserId(message.sender)
|
||||
let avatarURL = memberDetailProvider.avatarURLForUserId(message.sender)
|
||||
let avatarImage = mediaProvider.imageFromURL(avatarURL)
|
||||
|
||||
switch roomMessage {
|
||||
switch message {
|
||||
case let message as TextRoomMessage:
|
||||
return buildTextTimelineItemFromMessage(message, showSenderDetails, displayName, avatarImage)
|
||||
case let message as ImageRoomMessage:
|
||||
|
@ -0,0 +1,14 @@
|
||||
//
|
||||
// RoomTimelineItemFactoryProtocol.swift
|
||||
// ElementX
|
||||
//
|
||||
// Created by Stefan Ceriu on 26/05/2022.
|
||||
// Copyright © 2022 element.io. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@MainActor
|
||||
protocol RoomTimelineItemFactoryProtocol {
|
||||
func buildTimelineItemFor(message: RoomMessageProtocol, showSenderDetails: Bool) -> RoomTimelineItemProtocol
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
//
|
||||
// TimelineViewFactory.swift
|
||||
// RoomTimelineViewFactory.swift
|
||||
// ElementX
|
||||
//
|
||||
// Created by Stefan Ceriu on 16/03/2022.
|
||||
@ -8,9 +8,8 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
@MainActor
|
||||
struct RoomTimelineViewFactory {
|
||||
func buildTimelineViewFor(_ timelineItem: RoomTimelineItemProtocol) -> RoomTimelineViewProvider {
|
||||
struct RoomTimelineViewFactory: RoomTimelineViewFactoryProtocol {
|
||||
func buildTimelineViewFor(timelineItem: RoomTimelineItemProtocol) -> RoomTimelineViewProvider {
|
||||
switch timelineItem {
|
||||
case let item as TextRoomTimelineItem:
|
||||
return .text(item)
|
||||
|
@ -0,0 +1,14 @@
|
||||
//
|
||||
// RoomTimelineViewFactoryProtocol.swift
|
||||
// ElementX
|
||||
//
|
||||
// Created by Stefan Ceriu on 26/05/2022.
|
||||
// Copyright © 2022 element.io. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@MainActor
|
||||
protocol RoomTimelineViewFactoryProtocol {
|
||||
func buildTimelineViewFor(timelineItem: RoomTimelineItemProtocol) -> RoomTimelineViewProvider
|
||||
}
|
@ -22,7 +22,7 @@ class UITestsAppCoordinator: Coordinator {
|
||||
|
||||
let screens = mockScreens()
|
||||
let rootView = UITestsRootView(mockScreens: screens) { id in
|
||||
guard let screen = screens.filter({ $0.id == id }).first else {
|
||||
guard let screen = screens.first(where: { $0.id == id }) else {
|
||||
fatalError()
|
||||
}
|
||||
|
||||
|
@ -16,8 +16,7 @@
|
||||
|
||||
import SwiftUI
|
||||
|
||||
typealias TemplateSimpleScreenViewModelType = StateStoreViewModel<TemplateSimpleScreenViewState,
|
||||
TemplateSimpleScreenViewAction>
|
||||
typealias TemplateSimpleScreenViewModelType = StateStoreViewModel<TemplateSimpleScreenViewState, TemplateSimpleScreenViewAction>
|
||||
|
||||
class TemplateSimpleScreenViewModel: TemplateSimpleScreenViewModelType, TemplateSimpleScreenViewModelProtocol {
|
||||
|
||||
@ -34,10 +33,10 @@ class TemplateSimpleScreenViewModel: TemplateSimpleScreenViewModelType, Template
|
||||
init(promptType: TemplateSimpleScreenPromptType, initialCount: Int = 0) {
|
||||
super.init(initialViewState: TemplateSimpleScreenViewState(promptType: promptType, count: 0))
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Public
|
||||
|
||||
override func process(viewAction: TemplateSimpleScreenViewAction) {
|
||||
|
||||
override func process(viewAction: TemplateSimpleScreenViewAction) async {
|
||||
switch viewAction {
|
||||
case .accept:
|
||||
completion?(.accept)
|
||||
|
@ -36,14 +36,17 @@ class TemplateSimpleScreenViewModelTests: XCTestCase {
|
||||
XCTAssertEqual(context.viewState.count, Constants.counterInitialValue)
|
||||
}
|
||||
|
||||
func testCounter() throws {
|
||||
func testCounter() async throws {
|
||||
context.send(viewAction: .incrementCount)
|
||||
await Task.yield()
|
||||
XCTAssertEqual(context.viewState.count, 1)
|
||||
|
||||
context.send(viewAction: .incrementCount)
|
||||
await Task.yield()
|
||||
XCTAssertEqual(context.viewState.count, 2)
|
||||
|
||||
context.send(viewAction: .decrementCount)
|
||||
await Task.yield()
|
||||
XCTAssertEqual(context.viewState.count, 1)
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user