Display avatars full screen when tapping on them from the room or member detail screens

This commit is contained in:
Stefan Ceriu
2023-08-04 15:44:37 +03:00
committed by Stefan Ceriu
parent 68f8bfed53
commit 3515494a10
13 changed files with 132 additions and 22 deletions
@@ -20,6 +20,7 @@ struct RoomMemberDetailsScreenCoordinatorParameters {
let roomProxy: RoomProxyProtocol
let roomMemberProxy: RoomMemberProxyProtocol
let mediaProvider: MediaProviderProtocol
let userIndicatorController: UserIndicatorControllerProtocol
}
enum RoomMemberDetailsScreenCoordinatorAction { }
@@ -35,7 +36,8 @@ final class RoomMemberDetailsScreenCoordinator: CoordinatorProtocol {
viewModel = RoomMemberDetailsScreenViewModel(roomProxy: parameters.roomProxy,
roomMemberProxy: parameters.roomMemberProxy,
mediaProvider: parameters.mediaProvider)
mediaProvider: parameters.mediaProvider,
userIndicatorController: parameters.userIndicatorController)
}
func start() { }
@@ -66,6 +66,9 @@ struct RoomMemberDetailsScreenViewStateBindings {
var ignoreUserAlert: IgnoreUserAlertItem?
var alertInfo: AlertInfo<RoomMemberDetailsScreenError>?
/// A media item that will be previewed with QuickLook.
var mediaPreviewItem: MediaPreviewItem?
}
enum RoomMemberDetailsScreenViewAction {
@@ -73,6 +76,7 @@ enum RoomMemberDetailsScreenViewAction {
case showIgnoreAlert
case ignoreConfirmed
case unignoreConfirmed
case displayAvatar
}
enum RoomMemberDetailsScreenError: Hashable {
@@ -21,14 +21,23 @@ typealias RoomMemberDetailsScreenViewModelType = StateStoreViewModel<RoomMemberD
class RoomMemberDetailsScreenViewModel: RoomMemberDetailsScreenViewModelType, RoomMemberDetailsScreenViewModelProtocol {
private let roomProxy: RoomProxyProtocol
private let roomMemberProxy: RoomMemberProxyProtocol
private let mediaProvider: MediaProviderProtocol
private let userIndicatorController: UserIndicatorControllerProtocol
var callback: ((RoomMemberDetailsScreenViewModelAction) -> Void)?
init(roomProxy: RoomProxyProtocol, roomMemberProxy: RoomMemberProxyProtocol, mediaProvider: MediaProviderProtocol) {
init(roomProxy: RoomProxyProtocol,
roomMemberProxy: RoomMemberProxyProtocol,
mediaProvider: MediaProviderProtocol,
userIndicatorController: UserIndicatorControllerProtocol) {
self.roomProxy = roomProxy
self.roomMemberProxy = roomMemberProxy
self.mediaProvider = mediaProvider
self.userIndicatorController = userIndicatorController
let initialViewState = RoomMemberDetailsScreenViewState(details: RoomMemberDetails(withProxy: roomMemberProxy),
bindings: .init())
super.init(initialViewState: initialViewState, imageProvider: mediaProvider)
}
@@ -44,6 +53,8 @@ class RoomMemberDetailsScreenViewModel: RoomMemberDetailsScreenViewModelType, Ro
Task { await ignoreUser() }
case .unignoreConfirmed:
Task { await unignoreUser() }
case .displayAvatar:
displayFullScreenAvatar()
}
}
@@ -82,4 +93,24 @@ class RoomMemberDetailsScreenViewModel: RoomMemberDetailsScreenViewModelType, Ro
await self.roomProxy.updateMembers()
}
}
private func displayFullScreenAvatar() {
guard let avatarURL = roomMemberProxy.avatarURL else {
return
}
let loadingIndicatorIdentifier = "roomMemberAvatarLoadingIndicator"
userIndicatorController.submitIndicator(UserIndicator(id: loadingIndicatorIdentifier, type: .modal, title: L10n.commonLoading, persistent: true))
Task {
defer {
userIndicatorController.retractIndicatorWithId(loadingIndicatorIdentifier)
}
// We don't actually know the mime type here, assume it's an image.
if case let .success(file) = await mediaProvider.loadFileFromSource(.init(url: avatarURL, mimeType: "image/jpeg")) {
state.bindings.mediaPreviewItem = MediaPreviewItem(file: file, title: roomMemberProxy.displayName)
}
}
}
}
@@ -31,6 +31,7 @@ struct RoomMemberDetailsScreen: View {
.alert(item: $context.ignoreUserAlert, actions: blockUserAlertActions, message: blockUserAlertMessage)
.alert(item: $context.alertInfo)
.track(screen: .user)
.interactiveQuickLook(item: $context.mediaPreviewItem)
}
// MARK: - Private
@@ -43,6 +44,8 @@ struct RoomMemberDetailsScreen: View {
avatarSize: .user(on: .memberDetails),
imageProvider: context.imageProvider,
subtitle: context.viewState.details.id) {
context.send(viewAction: .displayAvatar)
} footer: {
if let permalink = context.viewState.details.permalink {
HStack(spacing: 32) {
ShareLink(item: permalink) {
@@ -101,17 +104,26 @@ struct RoomMemberDetailsScreen_Previews: PreviewProvider {
static let roomProxyMock = RoomProxyMock(with: .init(displayName: ""))
static let otherUserViewModel = {
let member = RoomMemberProxyMock.mockDan
return RoomMemberDetailsScreenViewModel(roomProxy: roomProxyMock, roomMemberProxy: member, mediaProvider: MockMediaProvider())
return RoomMemberDetailsScreenViewModel(roomProxy: roomProxyMock,
roomMemberProxy: member,
mediaProvider: MockMediaProvider(),
userIndicatorController: ServiceLocator.shared.userIndicatorController)
}()
static let accountOwnerViewModel = {
let member = RoomMemberProxyMock.mockMe
return RoomMemberDetailsScreenViewModel(roomProxy: roomProxyMock, roomMemberProxy: member, mediaProvider: MockMediaProvider())
return RoomMemberDetailsScreenViewModel(roomProxy: roomProxyMock,
roomMemberProxy: member,
mediaProvider: MockMediaProvider(),
userIndicatorController: ServiceLocator.shared.userIndicatorController)
}()
static let ignoredUserViewModel = {
let member = RoomMemberProxyMock.mockIgnored
return RoomMemberDetailsScreenViewModel(roomProxy: roomProxyMock, roomMemberProxy: member, mediaProvider: MockMediaProvider())
return RoomMemberDetailsScreenViewModel(roomProxy: roomProxyMock,
roomMemberProxy: member,
mediaProvider: MockMediaProvider(),
userIndicatorController: ServiceLocator.shared.userIndicatorController)
}()
static var previews: some View {