Room's details edit screen (#956)

* Add RoomDetailsEditScreen template

* Add navigation to the edit screen

* Delete template code

* Start RoomDetailsEditScreen UI

* Manage power levels in RoomDetailsScreen

* Start RoomDetailsEditScreenViewModel logic

* Inject initial room state

* Add cancel action

* Expose set name/topic APIs in RoomProxy

* Refine RoomDetailsEditScreen UI

* Add save logic

* Add localisations

* Fix avatar image

* Update localisations

* Add “Add topic” button

* Add feature flag

* Add dismiss on save logic

* Reduce throttling

* Improve form logic

* Fix UT build errors

* Add media sheet

* Add media preprocessing

* Add LoadableEditableAvatarImage

* Add condition on delete image

* Add avatar save button logic

* Add remove avatar logic

* Cleanup

* Fix edit bug in DM

* Add upload avatar

* Add focus

* Add RoomDetailsViewModel UTs

* Fix button style

* Add UTs

* Add empty topic ui test

* Fix iPad sheet presentation

* Revert topic appearance in room’s details

* Address PR comments

* Add UI tests
This commit is contained in:
Alfonso Grillo
2023-05-26 15:47:12 +02:00
committed by GitHub
parent 524997438f
commit f2b7faa183
47 changed files with 1281 additions and 54 deletions
@@ -70,6 +70,10 @@ final class RoomMemberProxy: RoomMemberProxyProtocol {
var canInviteUsers: Bool {
member.canInvite()
}
func canSendStateEvent(type: StateEventType) -> Bool {
member.canSendState(stateEvent: type)
}
func ignoreUser() async -> Result<Void, RoomMemberProxyError> {
sendAccountDataEventBackgroundTask = await backgroundTaskService.startBackgroundTask(withName: backgroundAccountDataTaskName, isReusable: true)
@@ -37,6 +37,7 @@ protocol RoomMemberProxyProtocol {
func ignoreUser() async -> Result<Void, RoomMemberProxyError>
func unignoreUser() async -> Result<Void, RoomMemberProxyError>
func canSendStateEvent(type: StateEventType) -> Bool
}
extension RoomMemberProxyProtocol {
+52 -7
View File
@@ -130,7 +130,19 @@ class RoomProxy: RoomProxyProtocol {
// return trusted image for now, should be updated after verification status known
return Asset.Images.encryptionTrusted.image
}
var invitedMembersCount: UInt {
UInt(room.invitedMembersCount())
}
var joinedMembersCount: UInt {
UInt(room.joinedMembersCount())
}
var activeMembersCount: UInt {
UInt(room.activeMembersCount())
}
func loadAvatarURLForUserId(_ userId: String) async -> Result<URL?, RoomProxyError> {
do {
guard let urlString = try await Task.dispatch(on: lowPriorityDispatchQueue, {
@@ -486,18 +498,51 @@ class RoomProxy: RoomProxyProtocol {
}
}
var invitedMembersCount: UInt {
UInt(room.invitedMembersCount())
func setName(_ name: String?) async -> Result<Void, RoomProxyError> {
await Task.dispatch(on: .global()) {
do {
return try .success(self.room.setName(name: name))
} catch {
return .failure(.failedSettingRoomName)
}
}
}
func setTopic(_ topic: String) async -> Result<Void, RoomProxyError> {
await Task.dispatch(on: .global()) {
do {
return try .success(self.room.setTopic(topic: topic))
} catch {
return .failure(.failedSettingRoomTopic)
}
}
}
var joinedMembersCount: UInt {
UInt(room.joinedMembersCount())
func removeAvatar() async -> Result<Void, RoomProxyError> {
await Task.dispatch(on: .global()) {
do {
return try .success(self.room.removeAvatar())
} catch {
return .failure(.failedRemovingAvatar)
}
}
}
var activeMembersCount: UInt {
UInt(room.activeMembersCount())
func uploadAvatar(media: MediaInfo) async -> Result<Void, RoomProxyError> {
await Task.dispatch(on: .global()) {
guard case let .image(imageURL, _, _) = media, let mimeType = media.mimeType else {
return .failure(.failedUploadingAvatar)
}
do {
let data = try Data(contentsOf: imageURL)
return try .success(self.room.uploadAvatar(mimeType: mimeType, data: [UInt8](data)))
} catch {
return .failure(.failedUploadingAvatar)
}
}
}
// MARK: - Private
/// Force the timeline to load member details so it can populate sender profiles whenever we add a timeline listener
@@ -37,6 +37,10 @@ enum RoomProxyError: Error {
case failedAcceptingInvite
case failedRejectingInvite
case failedInvitingUser
case failedSettingRoomName
case failedSettingRoomTopic
case failedRemovingAvatar
case failedUploadingAvatar
}
@MainActor
@@ -61,6 +65,12 @@ protocol RoomProxyProtocol {
var membersPublisher: AnyPublisher<[RoomMemberProxyProtocol], Never> { get }
var invitedMembersCount: UInt { get }
var joinedMembersCount: UInt { get }
var activeMembersCount: UInt { get }
/// Publishes the room's updates.
/// The publisher starts publishing after the first call to `registerTimelineListenerIfNeeded()`
/// The thread on which this publisher sends the output isn't defined.
@@ -114,11 +124,13 @@ protocol RoomProxyProtocol {
func invite(userID: String) async -> Result<Void, RoomProxyError>
var invitedMembersCount: UInt { get }
func setName(_ name: String?) async -> Result<Void, RoomProxyError>
var joinedMembersCount: UInt { get }
func setTopic(_ topic: String) async -> Result<Void, RoomProxyError>
var activeMembersCount: UInt { get }
func removeAvatar() async -> Result<Void, RoomProxyError>
func uploadAvatar(media: MediaInfo) async -> Result<Void, RoomProxyError>
}
extension RoomProxyProtocol {