mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-02 21:33:26 +00:00
Concurrency Fixes (#283)
* Review places where MainActor used * Adapt to MainActor changes, avoid redundant task detachments * Move Rust client operations into a dedicated concurrent queue, make init async * Add changelog * Fixed small working for awaiting non-async method * Remove some redundant tasks * Put back some main actors * Fix tests * Fixed timeline updates when the number of items doesn't change. Keeps more previous home screen room data between reloads Co-authored-by: Stefan Ceriu <stefanc@matrix.org>
This commit is contained in:
@@ -23,6 +23,7 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
|
||||
private let userSession: UserSessionProtocol
|
||||
private let roomSummaryProvider: RoomSummaryProviderProtocol
|
||||
private let attributedStringBuilder: AttributedStringBuilderProtocol
|
||||
private var roomsForIdentifiers = [String: HomeScreenRoom]()
|
||||
|
||||
var callback: ((HomeScreenViewModelAction) -> Void)?
|
||||
|
||||
@@ -72,9 +73,7 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
|
||||
roomSummaryProvider.roomListPublisher
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] _ in
|
||||
Task {
|
||||
await self?.updateRooms()
|
||||
}
|
||||
self?.updateRooms()
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
@@ -91,10 +90,8 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
|
||||
state.userDisplayName = userDisplayName
|
||||
}
|
||||
}
|
||||
|
||||
Task {
|
||||
await updateRooms()
|
||||
}
|
||||
|
||||
updateRooms()
|
||||
}
|
||||
|
||||
// MARK: - Public
|
||||
@@ -117,52 +114,58 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
|
||||
// MARK: - Private
|
||||
|
||||
private func loadDataForRoomIdentifier(_ identifier: String) {
|
||||
guard let summary = roomSummaryProvider.roomListPublisher.value.first(where: { $0.asFilled?.id == identifier })?.asFilled,
|
||||
let homeRoomIndex = state.rooms.firstIndex(where: { $0.id == identifier }) else {
|
||||
guard let roomSummary = roomSummaryProvider.roomListPublisher.value.first(where: { $0.asFilled?.id == identifier })?.asFilled,
|
||||
let roomIndex = state.rooms.firstIndex(where: { $0.id == identifier }) else {
|
||||
return
|
||||
}
|
||||
|
||||
var details = state.rooms[homeRoomIndex]
|
||||
var room = state.rooms[roomIndex]
|
||||
|
||||
guard details.avatar == nil,
|
||||
let avatarURLString = summary.avatarURLString else {
|
||||
guard room.avatar == nil,
|
||||
let avatarURLString = roomSummary.avatarURLString else {
|
||||
return
|
||||
}
|
||||
|
||||
Task {
|
||||
if case let .success(image) = await userSession.mediaProvider.loadImageFromURLString(avatarURLString, avatarSize: .room(on: .home)) {
|
||||
details.avatar = image
|
||||
state.rooms[homeRoomIndex] = details
|
||||
room.avatar = image
|
||||
state.rooms[roomIndex] = room
|
||||
roomsForIdentifiers[roomSummary.id] = room
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func updateRooms() async {
|
||||
state.rooms = await Task.detached {
|
||||
var rooms = [HomeScreenRoom]()
|
||||
|
||||
for summary in self.roomSummaryProvider.roomListPublisher.value {
|
||||
switch summary {
|
||||
case .empty(let id):
|
||||
rooms.append(HomeScreenRoom.placeholder(id: id))
|
||||
case .filled(let summary):
|
||||
let avatarImage = await self.userSession.mediaProvider.imageFromURLString(summary.avatarURLString, avatarSize: .room(on: .home))
|
||||
|
||||
var timestamp: String?
|
||||
if let lastMessageTimestamp = summary.lastMessageTimestamp {
|
||||
timestamp = lastMessageTimestamp.formatted(date: .omitted, time: .shortened)
|
||||
}
|
||||
|
||||
rooms.append(HomeScreenRoom(id: summary.id,
|
||||
name: summary.name,
|
||||
hasUnreads: summary.unreadNotificationCount > 0,
|
||||
timestamp: timestamp,
|
||||
lastMessage: summary.lastMessage,
|
||||
avatar: avatarImage))
|
||||
private func updateRooms() {
|
||||
var rooms = [HomeScreenRoom]()
|
||||
var newRoomsForIdentifiers = [String: HomeScreenRoom]()
|
||||
|
||||
for summary in roomSummaryProvider.roomListPublisher.value {
|
||||
switch summary {
|
||||
case .empty(let id):
|
||||
rooms.append(HomeScreenRoom.placeholder(id: id))
|
||||
case .filled(let summary):
|
||||
let oldRoom = roomsForIdentifiers[summary.id]
|
||||
|
||||
let avatarImage = userSession.mediaProvider.imageFromURLString(summary.avatarURLString, avatarSize: .room(on: .home))
|
||||
|
||||
var timestamp: String?
|
||||
if let lastMessageTimestamp = summary.lastMessageTimestamp {
|
||||
timestamp = lastMessageTimestamp.formatted(date: .omitted, time: .shortened)
|
||||
}
|
||||
|
||||
let room = HomeScreenRoom(id: summary.id,
|
||||
name: summary.name,
|
||||
hasUnreads: summary.unreadNotificationCount > 0,
|
||||
timestamp: timestamp ?? oldRoom?.timestamp,
|
||||
lastMessage: summary.lastMessage ?? oldRoom?.lastMessage,
|
||||
avatar: avatarImage ?? oldRoom?.avatar)
|
||||
|
||||
rooms.append(room)
|
||||
newRoomsForIdentifiers[summary.id] = room
|
||||
}
|
||||
|
||||
return rooms
|
||||
}.value
|
||||
}
|
||||
|
||||
state.rooms = rooms
|
||||
roomsForIdentifiers = newRoomsForIdentifiers
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user