mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-03 16:10:20 +00:00
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:
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user