diff --git a/Riot/Modules/Common/Avatar/AvatarView.swift b/Riot/Modules/Common/Avatar/AvatarView.swift index 54afc868a..210943386 100644 --- a/Riot/Modules/Common/Avatar/AvatarView.swift +++ b/Riot/Modules/Common/Avatar/AvatarView.swift @@ -32,7 +32,7 @@ class AvatarView: UIView, Themable { // MARK: Private - private var theme: Theme? + private(set) var theme: Theme? // MARK: Public @@ -106,7 +106,18 @@ class AvatarView: UIView, Themable { return } - let defaultavatarImage = AvatarGenerator.generateAvatar(forMatrixItem: viewData.matrixItemId, withDisplayName: viewData.displayName) + let defaultAvatarImage: UIImage? + var defaultAvatarImageContentMode: UIView.ContentMode = .scaleAspectFill + + switch viewData.fallbackImage { + case .matrixItem(let matrixItemId, let matrixItemDisplayName): + defaultAvatarImage = AvatarGenerator.generateAvatar(forMatrixItem: matrixItemId, withDisplayName: matrixItemDisplayName) + case .image(let image, let contentMode): + defaultAvatarImage = image + defaultAvatarImageContentMode = contentMode ?? .scaleAspectFill + case .none: + defaultAvatarImage = nil + } if let avatarUrl = viewData.avatarUrl { avatarImageView.setImageURI(avatarUrl, @@ -114,13 +125,13 @@ class AvatarView: UIView, Themable { andImageOrientation: .up, toFitViewSize: avatarImageView.frame.size, with: MXThumbnailingMethodScale, - previewImage: defaultavatarImage, + previewImage: defaultAvatarImage, mediaManager: viewData.mediaManager) + avatarImageView.contentMode = .scaleAspectFill } else { - avatarImageView.image = defaultavatarImage + avatarImageView.image = defaultAvatarImage + avatarImageView.contentMode = defaultAvatarImageContentMode } - - avatarImageView.contentMode = .scaleAspectFill } func updateView() { diff --git a/Riot/Modules/Common/Avatar/AvatarViewData.swift b/Riot/Modules/Common/Avatar/AvatarViewData.swift new file mode 100644 index 000000000..b9f676dff --- /dev/null +++ b/Riot/Modules/Common/Avatar/AvatarViewData.swift @@ -0,0 +1,29 @@ +// +// Copyright 2021 New Vector Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Foundation + +struct AvatarViewData: AvatarViewDataProtocol { + + /// Matrix item avatar URL (user or room avatar url) + var avatarUrl: String? + + /// Matrix media handler + var mediaManager: MXMediaManager + + /// Fallback image used when avatarUrl is nil + var fallbackImage: AvatarFallbackImage? +} diff --git a/Riot/Modules/Common/Avatar/AvatarViewDataProtocol.swift b/Riot/Modules/Common/Avatar/AvatarViewDataProtocol.swift index b63721ae4..a55dcc31b 100644 --- a/Riot/Modules/Common/Avatar/AvatarViewDataProtocol.swift +++ b/Riot/Modules/Common/Avatar/AvatarViewDataProtocol.swift @@ -14,19 +14,28 @@ // limitations under the License. // -import Foundation +import UIKit + +enum AvatarFallbackImage { + + /// matrixItem represent a Matrix item like a room, space, user + /// matrixItemId: Matrix item identifier (user id or room id) + /// displayName: Matrix item display name (user or room display name) + case matrixItem(_ matrixItemId: String, _ displayName: String?) + + /// Normal image with optional content mode + case image(_ image: UIImage, _ contentMode: UIView.ContentMode? = nil) +} /// AvatarViewDataProtocol describe a view data that should be given to an AvatarView sublcass protocol AvatarViewDataProtocol { - /// Matrix item identifier (user id or room id) - var matrixItemId: String { get } - - /// Matrix item display name (user or room display name) - var displayName: String? { get } /// Matrix item avatar URL (user or room avatar url) - var avatarUrl: String? { get } + var avatarUrl: String? { get } /// Matrix media handler var mediaManager: MXMediaManager { get } + + /// Fallback image used when avatarUrl is nil + var fallbackImage: AvatarFallbackImage? { get } } diff --git a/Riot/Modules/Room/Views/Avatar/RoomAvatarView.swift b/Riot/Modules/Room/Views/Avatar/RoomAvatarView.swift index 1b4612a36..6f6d79e86 100644 --- a/Riot/Modules/Room/Views/Avatar/RoomAvatarView.swift +++ b/Riot/Modules/Room/Views/Avatar/RoomAvatarView.swift @@ -25,7 +25,11 @@ final class RoomAvatarView: AvatarView, NibOwnerLoadable { @IBOutlet private weak var cameraBadgeContainerView: UIView! - // MARK: Setup + // MARK: Public + + var showCameraBadgeOnFallbackImage: Bool = false + + // MARK: - Setup private func commonInit() { } @@ -74,6 +78,14 @@ final class RoomAvatarView: AvatarView, NibOwnerLoadable { override func updateAvatarImageView(with viewData: AvatarViewDataProtocol) { super.updateAvatarImageView(with: viewData) - self.cameraBadgeContainerView.isHidden = viewData.avatarUrl != nil + let hideCameraBadge: Bool + + if self.showCameraBadgeOnFallbackImage { + hideCameraBadge = viewData.avatarUrl != nil + } else { + hideCameraBadge = true + } + + self.cameraBadgeContainerView.isHidden = hideCameraBadge } } diff --git a/Riot/Modules/Room/Views/Avatar/RoomAvatarViewData.swift b/Riot/Modules/Room/Views/Avatar/RoomAvatarViewData.swift index bf6f4888d..ee5d3ad81 100644 --- a/Riot/Modules/Room/Views/Avatar/RoomAvatarViewData.swift +++ b/Riot/Modules/Room/Views/Avatar/RoomAvatarViewData.swift @@ -25,4 +25,8 @@ struct RoomAvatarViewData: AvatarViewDataProtocol { var matrixItemId: String { return roomId } + + var fallbackImage: AvatarFallbackImage? { + return .matrixItem(matrixItemId, displayName) + } } diff --git a/Riot/Modules/User/Avatar/UserAvatarViewData.swift b/Riot/Modules/User/Avatar/UserAvatarViewData.swift index ce7be8ba6..25c5f46f5 100644 --- a/Riot/Modules/User/Avatar/UserAvatarViewData.swift +++ b/Riot/Modules/User/Avatar/UserAvatarViewData.swift @@ -25,4 +25,8 @@ struct UserAvatarViewData: AvatarViewDataProtocol { var matrixItemId: String { return userId } + + var fallbackImage: AvatarFallbackImage? { + return .matrixItem(matrixItemId, displayName) + } }