Skip to content

Commit

Permalink
Merge pull request #6927 from vector-im/alfogrillo/6847_avatar_image
Browse files Browse the repository at this point in the history
Update avatar image loading logics (PSB-198)
  • Loading branch information
Alfonso Grillo committed Oct 20, 2022
2 parents a30cc92 + 5043ece commit 1fd34d9
Show file tree
Hide file tree
Showing 9 changed files with 68 additions and 51 deletions.
31 changes: 14 additions & 17 deletions Riot/Modules/Common/Avatar/AvatarView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -106,19 +106,9 @@ class AvatarView: UIView, Themable {
return
}

let defaultAvatarImage: UIImage?
var defaultAvatarImageContentMode: UIView.ContentMode = .scaleAspectFill
let (defaultAvatarImage, defaultAvatarImageContentMode) = viewData.fallbackImageParameters() ?? (nil, .scaleAspectFill)
updateAvatarImageView(image: defaultAvatarImage, contentMode: defaultAvatarImageContentMode)

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,
withType: nil,
Expand All @@ -127,12 +117,9 @@ class AvatarView: UIView, Themable {
with: MXThumbnailingMethodScale,
previewImage: defaultAvatarImage,
mediaManager: viewData.mediaManager)
avatarImageView.contentMode = .scaleAspectFill
avatarImageView.imageView?.contentMode = .scaleAspectFill
updateAvatarContentMode(contentMode: .scaleAspectFill)
} else {
avatarImageView.image = defaultAvatarImage
avatarImageView.contentMode = defaultAvatarImageContentMode
avatarImageView.imageView?.contentMode = defaultAvatarImageContentMode
updateAvatarImageView(image: defaultAvatarImage, contentMode: defaultAvatarImageContentMode)
}
}

Expand All @@ -148,6 +135,16 @@ class AvatarView: UIView, Themable {
gestureRecognizer.minimumPressDuration = 0
self.addGestureRecognizer(gestureRecognizer)
}

private func updateAvatarImageView(image: UIImage?, contentMode: UIView.ContentMode) {
avatarImageView?.image = image
updateAvatarContentMode(contentMode: contentMode)
}

private func updateAvatarContentMode(contentMode: UIView.ContentMode) {
avatarImageView?.contentMode = contentMode
avatarImageView?.imageView.contentMode = contentMode
}

// MARK: - Actions

Expand Down
19 changes: 17 additions & 2 deletions Riot/Modules/Common/Avatar/AvatarViewData.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,21 @@ struct AvatarViewData: AvatarViewDataProtocol {
/// Matrix media handler if exists
var mediaManager: MXMediaManager?

/// Fallback image used when avatarUrl is nil
var fallbackImage: AvatarFallbackImage?
/// Fallback images used when avatarUrl is nil
var fallbackImages: [AvatarFallbackImage]?
}

extension AvatarViewData {
init(matrixItemId: String,
displayName: String? = nil,
avatarUrl: String? = nil,
mediaManager: MXMediaManager? = nil,
fallbackImage: AvatarFallbackImage?) {

self.matrixItemId = matrixItemId
self.displayName = displayName
self.avatarUrl = avatarUrl
self.mediaManager = mediaManager
self.fallbackImages = fallbackImage.map { [$0] }
}
}
22 changes: 20 additions & 2 deletions Riot/Modules/Common/Avatar/AvatarViewDataProtocol.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,24 @@ protocol AvatarViewDataProtocol: AvatarProtocol {
/// Matrix media handler
var mediaManager: MXMediaManager? { get }

/// Fallback image used when avatarUrl is nil
var fallbackImage: AvatarFallbackImage? { get }
/// Fallback images used when avatarUrl is nil
var fallbackImages: [AvatarFallbackImage]? { get }
}

extension AvatarViewDataProtocol {
func fallbackImageParameters() -> (UIImage?, UIView.ContentMode)? {
fallbackImages?
.lazy
.map { fallbackImage in
switch fallbackImage {
case .matrixItem(let matrixItemId, let matrixItemDisplayName):
return (AvatarGenerator.generateAvatar(forMatrixItem: matrixItemId, withDisplayName: matrixItemDisplayName), .scaleAspectFill)
case .image(let image, let contentMode):
return (image, contentMode ?? .scaleAspectFill)
}
}
.first { (image, contentMode) in
image != nil
}
}
}
22 changes: 10 additions & 12 deletions Riot/Modules/Home/AllChats/AllChatsCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ class AllChatsCoordinator: NSObject, SplitViewMasterCoordinatorProtocol {
createAvatarButtonItem(for: viewController)
}

private func createAvatarButtonItem(for viewController: UIViewController) {
private var avatarMenu: UIMenu {
var actions: [UIMenuElement] = []

actions.append(UIAction(title: VectorL10n.allChatsUserMenuSettings, image: UIImage(systemName: "gearshape")) { [weak self] action in
Expand All @@ -358,32 +358,30 @@ class AllChatsCoordinator: NSObject, SplitViewMasterCoordinatorProtocol {
}
]))

let menu = UIMenu(options: .displayInline, children: actions)

return UIMenu(options: .displayInline, children: actions)
}

private func createAvatarButtonItem(for viewController: UIViewController) {
let view = UIView(frame: CGRect(x: 0, y: 0, width: 36, height: 36))
view.backgroundColor = .clear

let button: UIButton = UIButton(frame: view.bounds.inset(by: UIEdgeInsets(top: 7, left: 7, bottom: 7, right: 7)))
let avatarInsets: UIEdgeInsets = .init(top: 7, left: 7, bottom: 7, right: 7)
let button: UIButton = .init(frame: view.bounds.inset(by: avatarInsets))
button.setImage(Asset.Images.tabPeople.image, for: .normal)
button.menu = menu
button.menu = avatarMenu
button.showsMenuAsPrimaryAction = true
button.autoresizingMask = [.flexibleHeight, .flexibleWidth]
button.accessibilityLabel = VectorL10n.allChatsUserMenuAccessibilityLabel
view.addSubview(button)
self.avatarMenuButton = button

let avatarView = UserAvatarView(frame: view.bounds.inset(by: UIEdgeInsets(top: 7, left: 7, bottom: 7, right: 7)))
let avatarView = UserAvatarView(frame: view.bounds.inset(by: avatarInsets))
avatarView.isUserInteractionEnabled = false
avatarView.update(theme: ThemeService.shared().theme)
avatarView.autoresizingMask = [.flexibleHeight, .flexibleWidth]
view.addSubview(avatarView)
self.avatarMenuView = avatarView

if let avatar = userAvatarViewData(from: currentMatrixSession) {
avatarView.fill(with: avatar)
button.setImage(nil, for: .normal)
}

updateAvatarButtonItem()
viewController.navigationItem.leftBarButtonItem = UIBarButtonItem(customView: view)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class RoomNotificationSettingsAvatarView: UIView {
func configure(viewData: AvatarViewDataProtocol) {
avatarView.fill(with: viewData)

switch viewData.fallbackImage {
switch viewData.fallbackImages?.first {
case .matrixItem(_, let matrixItemDisplayName):
nameLabel.text = matrixItemDisplayName
default:
Expand Down
4 changes: 2 additions & 2 deletions Riot/Modules/Room/Views/Avatar/RoomAvatarViewData.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ struct RoomAvatarViewData: AvatarViewDataProtocol {
return roomId
}

var fallbackImage: AvatarFallbackImage? {
return .matrixItem(matrixItemId, displayName)
var fallbackImages: [AvatarFallbackImage]? {
[.matrixItem(matrixItemId, displayName)]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,7 @@ struct DirectoryRoomTableViewCellVM {

// TODO: Use AvatarView subclass in the cell view
func setAvatar(in avatarImageView: MXKImageView) {

let defaultAvatarImage: UIImage?
var defaultAvatarImageContentMode: UIView.ContentMode = .scaleAspectFill

switch self.avatarViewData.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
}
let (defaultAvatarImage, defaultAvatarImageContentMode) = avatarViewData.fallbackImageParameters() ?? (nil, .scaleAspectFill)

if let avatarUrl = self.avatarViewData.avatarUrl {
avatarImageView.enableInMemoryCache = true
Expand Down
4 changes: 2 additions & 2 deletions Riot/Modules/User/Avatar/UserAvatarViewData.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ struct UserAvatarViewData: AvatarViewDataProtocol {
return userId
}

var fallbackImage: AvatarFallbackImage? {
return .matrixItem(matrixItemId, displayName)
var fallbackImages: [AvatarFallbackImage]? {
[.matrixItem(matrixItemId, displayName), .image(Asset.Images.tabPeople.image, .scaleAspectFill)]
}
}
1 change: 1 addition & 0 deletions changelog.d/6847.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Updates the avatar image loading logics.

0 comments on commit 1fd34d9

Please sign in to comment.