/* Copyright 2018-2024 New Vector Ltd. Copyright 2017 Vector Creations Ltd Copyright 2015 OpenMarket Ltd SPDX-License-Identifier: AGPL-3.0-only Please see LICENSE in the repository root for full details. */ #import "MXKContactField.h" @import MatrixSDK.MXMediaManager; #import "MXKContactManager.h" @interface MXKContactField() { // Tell whether we already check the contact avatar definition. BOOL shouldCheckAvatarURL; // The media manager of the session used to retrieve the contect avatar url // This manager is used to download this avatar if need MXMediaManager *mediaManager; // The current download id NSString *downloadId; } @end @implementation MXKContactField - (void)initFields { // init members _contactID = nil; _matrixID = nil; [self resetMatrixAvatar]; } - (id)initWithContactID:(NSString*)contactID matrixID:(NSString*)matrixID { self = [super init]; if (self) { [self initFields]; _contactID = contactID; _matrixID = matrixID; } return self; } - (void)resetMatrixAvatar { _avatarImage = nil; _matrixAvatarURL = nil; shouldCheckAvatarURL = YES; mediaManager = nil; downloadId = nil; } - (void)loadAvatarWithSize:(CGSize)avatarSize { // Check whether the avatar image is already set if (_avatarImage) { return; } // Sanity check if (_matrixID) { if (shouldCheckAvatarURL) { // Consider here all sessions reported into contact manager NSArray* mxSessions = [MXKContactManager sharedManager].mxSessions; if (mxSessions.count) { // Check whether a matrix user is already known MXUser* user; MXSession *mxSession; for (mxSession in mxSessions) { user = [mxSession userWithUserId:_matrixID]; if (user) { _matrixAvatarURL = user.avatarUrl; if (_matrixAvatarURL) { shouldCheckAvatarURL = NO; mediaManager = mxSession.mediaManager; [self downloadAvatarImage:avatarSize]; } break; } } // Trigger a server request if this url has not been found. if (shouldCheckAvatarURL) { MXWeakify(self); [mxSession.matrixRestClient avatarUrlForUser:_matrixID success:^(NSString *mxAvatarUrl) { MXStrongifyAndReturnIfNil(self); self.matrixAvatarURL = mxAvatarUrl; self->shouldCheckAvatarURL = NO; self->mediaManager = mxSession.mediaManager; [self downloadAvatarImage:avatarSize]; } failure:nil]; } } } else if (_matrixAvatarURL) { [self downloadAvatarImage:avatarSize]; } // Do nothing if the avatar url has been checked, and it is null. } } - (void)downloadAvatarImage:(CGSize)avatarSize { // the avatar image is already done if (_avatarImage) { return; } if (_matrixAvatarURL) { NSString *cacheFilePath = [MXMediaManager thumbnailCachePathForMatrixContentURI:_matrixAvatarURL andType:nil inFolder:kMXMediaManagerAvatarThumbnailFolder toFitViewSize:avatarSize withMethod:MXThumbnailingMethodCrop]; _avatarImage = [MXMediaManager loadPictureFromFilePath:cacheFilePath]; // the image is already in the cache if (_avatarImage) { MXWeakify(self); dispatch_async(dispatch_get_main_queue(), ^{ MXStrongifyAndReturnIfNil(self); [[NSNotificationCenter defaultCenter] postNotificationName:kMXKContactThumbnailUpdateNotification object:self.contactID userInfo:nil]; }); } else { NSString *downloadId = [MXMediaManager thumbnailDownloadIdForMatrixContentURI:_matrixAvatarURL inFolder:kMXMediaManagerAvatarThumbnailFolder toFitViewSize:avatarSize withMethod:MXThumbnailingMethodCrop]; MXMediaLoader* loader = [MXMediaManager existingDownloaderWithIdentifier:downloadId]; [[NSNotificationCenter defaultCenter] removeObserver:self name:kMXMediaLoaderStateDidChangeNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onMediaDownloadEnd:) name:kMXMediaLoaderStateDidChangeNotification object:loader]; if (!loader && mediaManager) { [mediaManager downloadThumbnailFromMatrixContentURI:_matrixAvatarURL withType:nil inFolder:kMXMediaManagerAvatarThumbnailFolder toFitViewSize:avatarSize withMethod:MXThumbnailingMethodCrop success:nil failure:nil]; } } } } - (void)onMediaDownloadEnd:(NSNotification *)notif { MXMediaLoader *loader = (MXMediaLoader*)notif.object; if ([loader.downloadId isEqualToString:downloadId]) { // update the image switch (loader.state) { case MXMediaLoaderStateDownloadCompleted: { UIImage *image = [MXMediaManager loadPictureFromFilePath:loader.downloadOutputFilePath]; if (image) { _avatarImage = image; MXWeakify(self); dispatch_async(dispatch_get_main_queue(), ^{ MXStrongifyAndReturnIfNil(self); [[NSNotificationCenter defaultCenter] postNotificationName:kMXKContactThumbnailUpdateNotification object:self.contactID userInfo:nil]; }); } [[NSNotificationCenter defaultCenter] removeObserver:self name:kMXMediaLoaderStateDidChangeNotification object:nil]; downloadId = nil; break; } case MXMediaLoaderStateDownloadFailed: case MXMediaLoaderStateCancelled: [[NSNotificationCenter defaultCenter] removeObserver:self name:kMXMediaLoaderStateDidChangeNotification object:nil]; downloadId = nil; break; default: break; } } } #pragma mark NSCoding - (id)initWithCoder:(NSCoder *)coder { if (self) { [self initFields]; _contactID = [coder decodeObjectForKey:@"contactID"]; _matrixID = [coder decodeObjectForKey:@"matrixID"]; } return self; } - (void)encodeWithCoder:(NSCoder *)coder { [coder encodeObject:_contactID forKey:@"contactID"]; [coder encodeObject:_matrixID forKey:@"matrixID"]; } @end