mirror of
https://gitlab.opencode.de/bwi/bundesmessenger/clients/bundesmessenger-ios.git
synced 2026-04-17 15:09:31 +02:00
Room details: fix content of attached videos, display picture in high res when user taps on the attachment, play the attached video too.
NOTE: The cache handling has been modified, the user should logout before installing this new version of iOS matrixConsole in order to clear the existing cache.
This commit is contained in:
@@ -8,11 +8,11 @@
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
D648B86A591308736E2D4078 /* libPods-matrixConsole.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8141B1E2401FFCC3C5B99234 /* libPods-matrixConsole.a */; };
|
||||
F00B5DB91A1B9BCE00EA1C8D /* CustomImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = F00B5DB81A1B9BCE00EA1C8D /* CustomImageView.m */; };
|
||||
F01628C119E29C660071C473 /* default-profile.png in Resources */ = {isa = PBXBuildFile; fileRef = F01628BC19E29C660071C473 /* default-profile.png */; };
|
||||
F01628C319E29C660071C473 /* logo.png in Resources */ = {isa = PBXBuildFile; fileRef = F01628BE19E29C660071C473 /* logo.png */; };
|
||||
F024098219E7D177006E741B /* tab_recents@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = F024098119E7D177006E741B /* tab_recents@2x.png */; };
|
||||
F02BCE231A1A5A2B00543B47 /* play.png in Resources */ = {isa = PBXBuildFile; fileRef = F02BCE221A1A5A2B00543B47 /* play.png */; };
|
||||
F02D707319F1CE4A007B47D3 /* CustomTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = F02D707219F1CE4A007B47D3 /* CustomTableViewCell.m */; };
|
||||
F02D707619F1DC9E007B47D3 /* RoomMemberTableCell.m in Sources */ = {isa = PBXBuildFile; fileRef = F02D707519F1DC9E007B47D3 /* RoomMemberTableCell.m */; };
|
||||
F03C47111A02952800E445AB /* CustomAlert.m in Sources */ = {isa = PBXBuildFile; fileRef = F03C47101A02952800E445AB /* CustomAlert.m */; };
|
||||
F03EF5F619F171EB00A0EE52 /* HomeViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = F03EF5EB19F171EB00A0EE52 /* HomeViewController.m */; };
|
||||
@@ -52,12 +52,12 @@
|
||||
13057A57E74FD5504196F47F /* Pods-matrixConsole.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-matrixConsole.release.xcconfig"; path = "Pods/Target Support Files/Pods-matrixConsole/Pods-matrixConsole.release.xcconfig"; sourceTree = "<group>"; };
|
||||
8141B1E2401FFCC3C5B99234 /* libPods-matrixConsole.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-matrixConsole.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
B7EC7E45C718BF2BBCE0CF48 /* Pods-matrixConsole.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-matrixConsole.debug.xcconfig"; path = "Pods/Target Support Files/Pods-matrixConsole/Pods-matrixConsole.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
F00B5DB71A1B9BCE00EA1C8D /* CustomImageView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CustomImageView.h; sourceTree = "<group>"; };
|
||||
F00B5DB81A1B9BCE00EA1C8D /* CustomImageView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CustomImageView.m; sourceTree = "<group>"; };
|
||||
F01628BC19E29C660071C473 /* default-profile.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "default-profile.png"; sourceTree = "<group>"; };
|
||||
F01628BE19E29C660071C473 /* logo.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = logo.png; sourceTree = "<group>"; };
|
||||
F024098119E7D177006E741B /* tab_recents@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "tab_recents@2x.png"; sourceTree = "<group>"; };
|
||||
F02BCE221A1A5A2B00543B47 /* play.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = play.png; sourceTree = "<group>"; };
|
||||
F02D707119F1CE4A007B47D3 /* CustomTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CustomTableViewCell.h; sourceTree = "<group>"; };
|
||||
F02D707219F1CE4A007B47D3 /* CustomTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CustomTableViewCell.m; sourceTree = "<group>"; };
|
||||
F02D707419F1DC9E007B47D3 /* RoomMemberTableCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RoomMemberTableCell.h; sourceTree = "<group>"; };
|
||||
F02D707519F1DC9E007B47D3 /* RoomMemberTableCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RoomMemberTableCell.m; sourceTree = "<group>"; };
|
||||
F03C470F1A02952800E445AB /* CustomAlert.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CustomAlert.h; sourceTree = "<group>"; };
|
||||
@@ -175,8 +175,8 @@
|
||||
F03EF5FC19F1762000A0EE52 /* View */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F02D707119F1CE4A007B47D3 /* CustomTableViewCell.h */,
|
||||
F02D707219F1CE4A007B47D3 /* CustomTableViewCell.m */,
|
||||
F00B5DB71A1B9BCE00EA1C8D /* CustomImageView.h */,
|
||||
F00B5DB81A1B9BCE00EA1C8D /* CustomImageView.m */,
|
||||
F02D707419F1DC9E007B47D3 /* RoomMemberTableCell.h */,
|
||||
F02D707519F1DC9E007B47D3 /* RoomMemberTableCell.m */,
|
||||
F03EF5FD19F1762000A0EE52 /* RoomMessageTableCell.h */,
|
||||
@@ -401,7 +401,6 @@
|
||||
files = (
|
||||
F07A80DB19DD9DE700B621A1 /* AppDelegate.m in Sources */,
|
||||
F03EF5FF19F1762000A0EE52 /* RoomMessageTableCell.m in Sources */,
|
||||
F02D707319F1CE4A007B47D3 /* CustomTableViewCell.m in Sources */,
|
||||
F07A80D819DD9DE700B621A1 /* main.m in Sources */,
|
||||
F05B955F19DEED8A008761B0 /* MatrixHandler.m in Sources */,
|
||||
F03EF5FB19F171EB00A0EE52 /* SettingsViewController.m in Sources */,
|
||||
@@ -412,6 +411,7 @@
|
||||
F03EF5F919F171EB00A0EE52 /* RecentsViewController.m in Sources */,
|
||||
F03C47111A02952800E445AB /* CustomAlert.m in Sources */,
|
||||
F02D707619F1DC9E007B47D3 /* RoomMemberTableCell.m in Sources */,
|
||||
F00B5DB91A1B9BCE00EA1C8D /* CustomImageView.m in Sources */,
|
||||
F0D3C30C1A011EF10000D49E /* AppSettings.m in Sources */,
|
||||
F03EF5F719F171EB00A0EE52 /* LoginViewController.m in Sources */,
|
||||
F0D3C30F1A01330F0000D49E /* SettingsTableViewCell.m in Sources */,
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Lq0-jR-3i5" id="iJp-sA-hG6">
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="default-profile.png" translatesAutoresizingMaskIntoConstraints="NO" id="uhu-R0-9NH">
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="default-profile.png" translatesAutoresizingMaskIntoConstraints="NO" id="uhu-R0-9NH" customClass="CustomImageView">
|
||||
<rect key="frame" x="8" y="5" width="40" height="40"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="40" id="ZJO-eO-xOQ"/>
|
||||
@@ -60,7 +60,7 @@
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
|
||||
</textView>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="mvK-ez-meg" userLabel="Attachment View">
|
||||
<imageView contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="mvK-ez-meg" userLabel="Attachment View" customClass="CustomImageView">
|
||||
<rect key="frame" x="59" y="28" width="184" height="14"/>
|
||||
</imageView>
|
||||
<imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="play.png" translatesAutoresizingMaskIntoConstraints="NO" id="vF4-rq-4Rn">
|
||||
@@ -155,7 +155,7 @@
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
|
||||
</textView>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="QZT-V8-yqJ" userLabel="Attachment View">
|
||||
<imageView contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="QZT-V8-yqJ" userLabel="Attachment View" customClass="CustomImageView">
|
||||
<rect key="frame" x="357" y="28" width="184" height="14"/>
|
||||
</imageView>
|
||||
<imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="play.png" translatesAutoresizingMaskIntoConstraints="NO" id="0Bl-Sv-Q2H">
|
||||
@@ -168,7 +168,7 @@
|
||||
<activityIndicatorView hidden="YES" opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" style="gray" translatesAutoresizingMaskIntoConstraints="NO" id="Pq8-lB-cZM">
|
||||
<rect key="frame" x="439" y="25" width="20" height="20"/>
|
||||
</activityIndicatorView>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="default-profile.png" translatesAutoresizingMaskIntoConstraints="NO" id="mks-jh-AiZ">
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="default-profile.png" translatesAutoresizingMaskIntoConstraints="NO" id="mks-jh-AiZ" customClass="CustomImageView">
|
||||
<rect key="frame" x="552" y="5" width="40" height="40"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="40" id="sGR-sG-6fA"/>
|
||||
@@ -322,7 +322,7 @@
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="kac-Vi-XbY" id="prD-ap-cDD">
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="default-profile.png" translatesAutoresizingMaskIntoConstraints="NO" id="RW8-nh-DTj">
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="default-profile.png" translatesAutoresizingMaskIntoConstraints="NO" id="RW8-nh-DTj" customClass="CustomImageView">
|
||||
<rect key="frame" x="8" y="5" width="40" height="40"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="40" id="4c3-8w-4Tg"/>
|
||||
|
||||
@@ -21,6 +21,7 @@ extern NSString *const kMediaManagerPrefixForDummyURL;
|
||||
|
||||
// The callback blocks
|
||||
typedef void (^blockMediaManager_onImageReady)(UIImage *image);
|
||||
typedef void (^blockMediaManager_onMediaReady)(NSString *cacheFilePath);
|
||||
typedef void (^blockMediaManager_onError)(NSError *error);
|
||||
|
||||
@interface MediaManager : NSObject
|
||||
@@ -32,13 +33,18 @@ typedef void (^blockMediaManager_onError)(NSError *error);
|
||||
// Load a picture from the local cache or download it if it is not available yet.
|
||||
// In this second case a mediaLoader reference is returned in order to let the user cancel this action.
|
||||
+ (id)loadPicture:(NSString *)pictureURL
|
||||
success:(blockMediaManager_onImageReady)success
|
||||
failure:(blockMediaManager_onError)failure;
|
||||
success:(blockMediaManager_onImageReady)success
|
||||
failure:(blockMediaManager_onError)failure;
|
||||
// Prepare a media from the local cache or download it if it is not available yet.
|
||||
// In this second case a mediaLoader reference is returned in order to let the user cancel this action.
|
||||
+ (id)prepareMedia:(NSString *)mediaURL
|
||||
mimeType:(NSString *)mimeType
|
||||
success:(blockMediaManager_onMediaReady)success
|
||||
failure:(blockMediaManager_onError)failure;
|
||||
+ (void)cancel:(id)mediaLoader;
|
||||
|
||||
+ (NSString *)cachePictureWithData:(NSData *)imageData forURL:(NSString *)pictureURL;
|
||||
+ (NSString *)cacheMediaData:(NSData *)mediaData forURL:(NSString *)mediaURL mimeType:(NSString *)mimeType;
|
||||
|
||||
+ (void)clearCacheForURL:(NSString *)mediaURL;
|
||||
+ (void)clearCache;
|
||||
|
||||
@end
|
||||
|
||||
@@ -18,15 +18,16 @@
|
||||
|
||||
NSString *const kMediaManagerPrefixForDummyURL = @"dummyUrl-";
|
||||
|
||||
static NSString* pictureCachePath = nil;
|
||||
static NSString *pictureDir = @"picturecache";
|
||||
static NSString* mediaCachePath = nil;
|
||||
static NSString *mediaDir = @"mediacache";
|
||||
|
||||
static MediaManager *sharedMediaManager = nil;
|
||||
|
||||
@interface MediaLoader : NSObject <NSURLConnectionDataDelegate> {
|
||||
NSString *mediaURL;
|
||||
NSString *mimeType;
|
||||
|
||||
blockMediaManager_onImageReady onImageReady;
|
||||
blockMediaManager_onMediaReady onMediaReady;
|
||||
blockMediaManager_onError onError;
|
||||
|
||||
NSMutableData *downloadData;
|
||||
@@ -41,20 +42,46 @@ static MediaManager *sharedMediaManager = nil;
|
||||
- (void)downloadPicture:(NSString*)pictureURL
|
||||
success:(blockMediaManager_onImageReady)success
|
||||
failure:(blockMediaManager_onError)failure {
|
||||
// Download picture content
|
||||
[self downloadMedia:pictureURL mimeType:@"image/jpeg" success:^(NSString *cacheFilePath) {
|
||||
if (success) {
|
||||
NSData* imageContent = [NSData dataWithContentsOfFile:cacheFilePath options:(NSDataReadingMappedAlways | NSDataReadingUncached) error:nil];
|
||||
if (imageContent) {
|
||||
UIImage *image = [UIImage imageWithData:imageContent];
|
||||
if (image) {
|
||||
success(image);
|
||||
} else {
|
||||
NSLog(@"ERROR: picture download failed: %@", pictureURL);
|
||||
if (failure){
|
||||
failure(nil);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} failure:^(NSError *error) {
|
||||
failure(error);
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)downloadMedia:(NSString*)aMediaURL
|
||||
mimeType:(NSString *)aMimeType
|
||||
success:(blockMediaManager_onMediaReady)success
|
||||
failure:(blockMediaManager_onError)failure {
|
||||
// Report provided params
|
||||
mediaURL = pictureURL;
|
||||
onImageReady = success;
|
||||
mediaURL = aMediaURL;
|
||||
mimeType = aMimeType;
|
||||
onMediaReady = success;
|
||||
onError = failure;
|
||||
|
||||
// Start downloading the picture
|
||||
NSURL *url = [NSURL URLWithString:pictureURL];
|
||||
// Start downloading
|
||||
NSURL *url = [NSURL URLWithString:aMediaURL];
|
||||
downloadData = [[NSMutableData alloc] init];
|
||||
downloadConnection = [[NSURLConnection alloc] initWithRequest:[NSURLRequest requestWithURL:url] delegate:self];
|
||||
}
|
||||
|
||||
- (void)cancel {
|
||||
// Reset blocks
|
||||
onImageReady = nil;
|
||||
onMediaReady = nil;
|
||||
onError = nil;
|
||||
// Cancel potential connection
|
||||
if (downloadConnection) {
|
||||
@@ -71,7 +98,7 @@ static MediaManager *sharedMediaManager = nil;
|
||||
#pragma mark -
|
||||
|
||||
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
|
||||
NSLog(@"ERROR: picture download failed: %@, %@", error, mediaURL);
|
||||
NSLog(@"ERROR: media download failed: %@, %@", error, mediaURL);
|
||||
if (onError) {
|
||||
onError (error);
|
||||
}
|
||||
@@ -83,18 +110,15 @@ static MediaManager *sharedMediaManager = nil;
|
||||
}
|
||||
|
||||
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
|
||||
// CAUTION: Presently only picture are supported
|
||||
// Set downloaded image
|
||||
UIImage *image = [UIImage imageWithData:downloadData];
|
||||
if (image) {
|
||||
if (downloadData.length) {
|
||||
// Cache the downloaded data
|
||||
[MediaManager cachePictureWithData:downloadData forURL:mediaURL];
|
||||
NSString *cacheFilePath = [MediaManager cacheMediaData:downloadData forURL:mediaURL mimeType:mimeType];
|
||||
// Call registered block
|
||||
if (onImageReady) {
|
||||
onImageReady(image);
|
||||
if (onMediaReady) {
|
||||
onMediaReady(cacheFilePath);
|
||||
}
|
||||
} else {
|
||||
NSLog(@"ERROR: picture download failed: %@", mediaURL);
|
||||
NSLog(@"ERROR: media download failed: %@", mediaURL);
|
||||
if (onError){
|
||||
onError(nil);
|
||||
}
|
||||
@@ -184,56 +208,73 @@ static MediaManager *sharedMediaManager = nil;
|
||||
return ret;
|
||||
}
|
||||
|
||||
+ (id)prepareMedia:(NSString *)mediaURL
|
||||
mimeType:(NSString *)mimeType
|
||||
success:(blockMediaManager_onMediaReady)success
|
||||
failure:(blockMediaManager_onError)failure {
|
||||
id ret = nil;
|
||||
// Check cache
|
||||
NSString* filename = [MediaManager getCacheFileNameFor:mediaURL mimeType:mimeType];
|
||||
if ([[NSFileManager defaultManager] fileExistsAtPath:filename]) {
|
||||
if (success) {
|
||||
// Reply synchronously
|
||||
success (filename);
|
||||
}
|
||||
}
|
||||
else if ([mediaURL hasPrefix:kMediaManagerPrefixForDummyURL] == NO) {
|
||||
// Create a media loader to download media content
|
||||
MediaLoader *mediaLoader = [[MediaLoader alloc] init];
|
||||
[mediaLoader downloadMedia:mediaURL mimeType:mimeType success:success failure:failure];
|
||||
ret = mediaLoader;
|
||||
} else {
|
||||
NSLog(@"Load tmp media from cache failed: %@", mediaURL);
|
||||
if (failure){
|
||||
failure(nil);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
+ (void)cancel:(id)mediaLoader {
|
||||
[((MediaLoader*)mediaLoader) cancel];
|
||||
}
|
||||
|
||||
+ (NSString*)cachePictureWithData:(NSData*)imageData forURL:(NSString *)pictureURL {
|
||||
NSString* filename = [MediaManager getCacheFileNameFor:pictureURL];
|
||||
+ (NSString*)cacheMediaData:(NSData*)mediaData forURL:(NSString *)mediaURL mimeType:(NSString *)mimeType {
|
||||
NSString* filename = [MediaManager getCacheFileNameFor:mediaURL mimeType:mimeType];
|
||||
|
||||
if ([imageData writeToFile:filename atomically:YES]) {
|
||||
if ([mediaData writeToFile:filename atomically:YES]) {
|
||||
return filename;
|
||||
} else {
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)clearCacheForURL:(NSString *)mediaURL {
|
||||
NSString* filename = [MediaManager getCacheFileNameFor:mediaURL];
|
||||
NSError *error = nil;
|
||||
if (filename && [[NSFileManager defaultManager] fileExistsAtPath:filename]) {
|
||||
if (![[NSFileManager defaultManager] removeItemAtPath:filename error:&error]) {
|
||||
NSLog(@"Fails to delete cached picture: %@", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)clearCache {
|
||||
NSError *error = nil;
|
||||
|
||||
if (!pictureCachePath) {
|
||||
if (!mediaCachePath) {
|
||||
// compute the path
|
||||
pictureCachePath = [MediaManager getCachePath];
|
||||
mediaCachePath = [MediaManager getCachePath];
|
||||
}
|
||||
|
||||
if (pictureCachePath) {
|
||||
if (![[NSFileManager defaultManager] removeItemAtPath:pictureCachePath error:&error]) {
|
||||
NSLog(@"Fails to delete picture cache dir : %@", error);
|
||||
if (mediaCachePath) {
|
||||
if (![[NSFileManager defaultManager] removeItemAtPath:mediaCachePath error:&error]) {
|
||||
NSLog(@"Fails to delete media cache dir : %@", error);
|
||||
} else {
|
||||
NSLog(@"Picture cache : deleted !");
|
||||
NSLog(@"Media cache : deleted !");
|
||||
}
|
||||
} else {
|
||||
NSLog(@"Picture cache does not exist");
|
||||
NSLog(@"Media cache does not exist");
|
||||
}
|
||||
|
||||
pictureCachePath = nil;
|
||||
mediaCachePath = nil;
|
||||
}
|
||||
|
||||
#pragma mark - Cache handling
|
||||
|
||||
+ (UIImage*)loadCachePicture:(NSString*)pictureURL {
|
||||
UIImage* res = nil;
|
||||
NSString* filename = [MediaManager getCacheFileNameFor:pictureURL];
|
||||
NSString* filename = [MediaManager getCacheFileNameFor:pictureURL mimeType:@"image/jpeg"];
|
||||
|
||||
if ([[NSFileManager defaultManager] fileExistsAtPath:filename]) {
|
||||
NSData* imageContent = [NSData dataWithContentsOfFile:filename options:(NSDataReadingMappedAlways | NSDataReadingUncached) error:nil];
|
||||
@@ -246,26 +287,41 @@ static MediaManager *sharedMediaManager = nil;
|
||||
}
|
||||
|
||||
+ (NSString*)getCachePath {
|
||||
NSString *mediaCachePath = nil;
|
||||
NSString *cachePath = nil;
|
||||
|
||||
if (!pictureCachePath) {
|
||||
if (!mediaCachePath) {
|
||||
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
|
||||
NSString *cacheRoot = [paths objectAtIndex:0];
|
||||
|
||||
pictureCachePath = [cacheRoot stringByAppendingPathComponent:pictureDir];
|
||||
mediaCachePath = [cacheRoot stringByAppendingPathComponent:mediaDir];
|
||||
|
||||
if (![[NSFileManager defaultManager] fileExistsAtPath:pictureCachePath]) {
|
||||
[[NSFileManager defaultManager] createDirectoryAtPath:pictureCachePath withIntermediateDirectories:NO attributes:nil error:nil];
|
||||
if (![[NSFileManager defaultManager] fileExistsAtPath:mediaCachePath]) {
|
||||
[[NSFileManager defaultManager] createDirectoryAtPath:mediaCachePath withIntermediateDirectories:NO attributes:nil error:nil];
|
||||
}
|
||||
}
|
||||
mediaCachePath = pictureCachePath;
|
||||
cachePath = mediaCachePath;
|
||||
|
||||
return mediaCachePath;
|
||||
return cachePath;
|
||||
}
|
||||
|
||||
+ (NSString*)getCacheFileNameFor:(NSString*)pictureURL {
|
||||
NSString* baseFileName = [[MediaManager getCachePath] stringByAppendingPathComponent:@"ima"];
|
||||
return [NSString stringWithFormat:@"%@%lu.jpg", baseFileName, (unsigned long)pictureURL.hash];
|
||||
+ (NSString*)getCacheFileNameFor:(NSString*)mediaURL mimeType:(NSString *)mimeType {
|
||||
NSString *fileName;
|
||||
if ([mimeType isEqualToString:@"image/jpeg"]) {
|
||||
fileName = [NSString stringWithFormat:@"ima%lu.jpg", (unsigned long)mediaURL.hash];
|
||||
} else if ([mimeType isEqualToString:@"video/mp4"]) {
|
||||
fileName = [NSString stringWithFormat:@"video%lu.mp4", (unsigned long)mediaURL.hash];
|
||||
} else if ([mimeType isEqualToString:@"video/quicktime"]) {
|
||||
fileName = [NSString stringWithFormat:@"video%lu.mov", (unsigned long)mediaURL.hash];
|
||||
} else {
|
||||
NSString *extension = @"";
|
||||
NSArray *components = [mediaURL componentsSeparatedByString:@"."];
|
||||
if (components && components.count > 1) {
|
||||
extension = [components lastObject];
|
||||
}
|
||||
fileName = [NSString stringWithFormat:@"%lu.%@", (unsigned long)mediaURL.hash, extension];
|
||||
}
|
||||
|
||||
return [[MediaManager getCachePath] stringByAppendingPathComponent:fileName];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -16,11 +16,12 @@
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
// Customize UITableViewCell in order to handle Table cell with UIImageView based on remote url
|
||||
@interface CustomTableViewCell : UITableViewCell
|
||||
@property (strong, nonatomic) IBOutlet UIImageView *pictureView;
|
||||
// Customize UIImageView in order to let UIImageView handle automatically remote url
|
||||
@interface CustomImageView : UIImageView
|
||||
|
||||
@property (strong, nonatomic) NSString *placeholder;
|
||||
@property (strong, nonatomic) NSString *pictureURL;
|
||||
@property (strong, nonatomic) NSString *imageURL;
|
||||
// Information about the media represented by this image (image, video...)
|
||||
@property (strong, nonatomic) NSDictionary *mediaInfo;
|
||||
@end
|
||||
|
||||
76
syMessaging/syMessaging/View/CustomImageView.m
Normal file
76
syMessaging/syMessaging/View/CustomImageView.m
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
Copyright 2014 OpenMarket 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 "CustomImageView.h"
|
||||
#import "MediaManager.h"
|
||||
|
||||
@interface CustomImageView () {
|
||||
id imageLoader;
|
||||
UIActivityIndicatorView *loadingWheel;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation CustomImageView
|
||||
|
||||
- (void)setImageURL:(NSString *)imageURL {
|
||||
// Cancel media loader in progress (if any)
|
||||
if (imageLoader) {
|
||||
[MediaManager cancel:imageLoader];
|
||||
imageLoader = nil;
|
||||
}
|
||||
|
||||
_imageURL = imageURL;
|
||||
|
||||
// Reset image view
|
||||
self.image = nil;
|
||||
if (_placeholder) {
|
||||
// Set picture placeholder
|
||||
self.image = [UIImage imageNamed:_placeholder];
|
||||
}
|
||||
// Consider provided url to update image view
|
||||
if (imageURL) {
|
||||
// Load picture
|
||||
if (loadingWheel == nil) {
|
||||
loadingWheel = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
|
||||
loadingWheel.center = self.center;
|
||||
[self addSubview:loadingWheel];
|
||||
}
|
||||
|
||||
[loadingWheel startAnimating];
|
||||
imageLoader = [MediaManager loadPicture:imageURL
|
||||
success:^(UIImage *image) {
|
||||
[loadingWheel stopAnimating];
|
||||
self.image = image;
|
||||
}
|
||||
failure:^(NSError *error) {
|
||||
[loadingWheel stopAnimating];
|
||||
NSLog(@"Failed to download image (%@): %@", imageURL, error);
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
if (imageLoader) {
|
||||
[MediaManager cancel:imageLoader];
|
||||
imageLoader = nil;
|
||||
}
|
||||
if (loadingWheel) {
|
||||
[loadingWheel removeFromSuperview];
|
||||
loadingWheel = nil;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
Copyright 2014 OpenMarket 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 "CustomTableViewCell.h"
|
||||
#import "MediaManager.h"
|
||||
|
||||
@interface CustomTableViewCell () {
|
||||
id userPictureLoader;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation CustomTableViewCell
|
||||
|
||||
- (void)setPictureURL:(NSString *)pictureURL {
|
||||
// Cancel media loader in progress (if any)
|
||||
if (userPictureLoader) {
|
||||
[MediaManager cancel:userPictureLoader];
|
||||
userPictureLoader = nil;
|
||||
}
|
||||
|
||||
_pictureURL = pictureURL;
|
||||
|
||||
// Reset image view
|
||||
_pictureView.image = nil;
|
||||
if (_placeholder) {
|
||||
// Set picture placeholder
|
||||
_pictureView.image = [UIImage imageNamed:_placeholder];
|
||||
}
|
||||
// Consider provided url to update image view
|
||||
if (pictureURL) {
|
||||
// Load picture
|
||||
userPictureLoader = [MediaManager loadPicture:pictureURL
|
||||
success:^(UIImage *image) {
|
||||
_pictureView.image = image;
|
||||
}
|
||||
failure:nil];
|
||||
}
|
||||
|
||||
// Round image view
|
||||
[_pictureView.layer setCornerRadius:_pictureView.frame.size.width / 2];
|
||||
_pictureView.clipsToBounds = YES;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
if (userPictureLoader) {
|
||||
[MediaManager cancel:userPictureLoader];
|
||||
userPictureLoader = nil;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -15,13 +15,14 @@
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "CustomTableViewCell.h"
|
||||
#import "CustomImageView.h"
|
||||
|
||||
@class MXRoomMember;
|
||||
@class MXRoom;
|
||||
|
||||
// Room Member Table View Cell
|
||||
@interface RoomMemberTableCell : CustomTableViewCell
|
||||
@interface RoomMemberTableCell : UITableViewCell
|
||||
@property (strong, nonatomic) IBOutlet CustomImageView *pictureView;
|
||||
@property (weak, nonatomic) IBOutlet UILabel *userLabel;
|
||||
@property (weak, nonatomic) IBOutlet UIProgressView *userPowerLevel;
|
||||
@property (weak, nonatomic) IBOutlet UILabel *lastActiveAgoLabel;
|
||||
|
||||
@@ -22,8 +22,11 @@
|
||||
- (void)setRoomMember:(MXRoomMember *)roomMember withRoom:(MXRoom *)room {
|
||||
if (room && roomMember) {
|
||||
self.userLabel.text = [room.state memberName:roomMember.userId];
|
||||
self.placeholder = @"default-profile";
|
||||
self.pictureURL = roomMember.avatarUrl;
|
||||
self.pictureView.placeholder = @"default-profile";
|
||||
self.pictureView.imageURL = roomMember.avatarUrl;
|
||||
// Round image view
|
||||
[self.pictureView.layer setCornerRadius:self.pictureView.frame.size.width / 2];
|
||||
self.pictureView.clipsToBounds = YES;
|
||||
|
||||
// Shade invited users
|
||||
if (roomMember.membership == MXMembershipInvite) {
|
||||
|
||||
@@ -15,12 +15,13 @@
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "CustomTableViewCell.h"
|
||||
#import "CustomImageView.h"
|
||||
|
||||
// Room Message Table View Cell
|
||||
@interface RoomMessageTableCell : CustomTableViewCell
|
||||
@interface RoomMessageTableCell : UITableViewCell
|
||||
@property (strong, nonatomic) IBOutlet CustomImageView *pictureView;
|
||||
@property (weak, nonatomic) IBOutlet UITextView *messageTextView;
|
||||
@property (strong, nonatomic) IBOutlet UIImageView *attachmentView;
|
||||
@property (strong, nonatomic) IBOutlet CustomImageView *attachmentView;
|
||||
@property (strong, nonatomic) IBOutlet UIImageView *playIconView;
|
||||
@property (weak, nonatomic) IBOutlet UILabel *dateTimeLabel;
|
||||
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *msgTextViewWidthConstraint;
|
||||
@@ -29,8 +30,6 @@
|
||||
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *dateTimeLabelTopConstraint;
|
||||
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *attachmentViewTopAlignmentConstraint;
|
||||
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *attachmentViewBottomAlignmentConstraint;
|
||||
|
||||
@property (strong, nonatomic) NSString *attachedImageURL;
|
||||
@end
|
||||
|
||||
@interface IncomingMessageTableCell : RoomMessageTableCell
|
||||
|
||||
@@ -17,45 +17,7 @@
|
||||
#import "RoomMessageTableCell.h"
|
||||
#import "MediaManager.h"
|
||||
|
||||
@interface RoomMessageTableCell () {
|
||||
id attachmentLoader;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation RoomMessageTableCell
|
||||
|
||||
- (void)setAttachedImageURL:(NSString *)attachedImageURL {
|
||||
// Cancel media loader in progress (if any)
|
||||
if (attachmentLoader) {
|
||||
[MediaManager cancel:attachmentLoader];
|
||||
attachmentLoader = nil;
|
||||
}
|
||||
|
||||
_attachedImageURL = attachedImageURL;
|
||||
|
||||
// Reset image view
|
||||
_attachmentView.image = nil;
|
||||
// Consider provided url to update image view
|
||||
if (attachedImageURL) {
|
||||
// Load picture
|
||||
attachmentLoader = [MediaManager loadPicture:attachedImageURL
|
||||
success:^(UIImage *image) {
|
||||
_attachmentView.image = image;
|
||||
}
|
||||
failure:^(NSError *error) {
|
||||
NSLog(@"Failed to download attachment (%@): %@", _attachedImageURL, error);
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
if (attachmentLoader) {
|
||||
[MediaManager cancel:attachmentLoader];
|
||||
attachmentLoader = nil;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
@@ -65,6 +65,11 @@ NSString *const kFailedEventId = @"failedEventId";
|
||||
NSArray *members;
|
||||
id membersListener;
|
||||
|
||||
// Attachment handling
|
||||
CustomImageView *highResImage;
|
||||
NSString *AVAudioSessionCategory;
|
||||
MPMoviePlayerController *videoPlayer;
|
||||
|
||||
// Date formatter (nil if dateTimeLabel is hidden)
|
||||
NSDateFormatter *dateFormatter;
|
||||
|
||||
@@ -122,11 +127,16 @@ NSString *const kFailedEventId = @"failedEventId";
|
||||
#endif
|
||||
// Clear temporary cached attachments (used for local echo)
|
||||
NSUInteger index = tmpCachedAttachments.count;
|
||||
NSError *error = nil;
|
||||
while (index--) {
|
||||
[MediaManager clearCacheForURL:[tmpCachedAttachments objectAtIndex:index]];
|
||||
if (![[NSFileManager defaultManager] removeItemAtPath:[tmpCachedAttachments objectAtIndex:index] error:&error]) {
|
||||
NSLog(@"Fail to delete cached media: %@", error);
|
||||
}
|
||||
}
|
||||
tmpCachedAttachments = nil;
|
||||
|
||||
[self hideAttachmentView];
|
||||
|
||||
messages = nil;
|
||||
if (messagesListener) {
|
||||
[mxRoom unregisterListener:messagesListener];
|
||||
@@ -230,10 +240,8 @@ NSString *const kFailedEventId = @"failedEventId";
|
||||
#ifdef TEMPORARY_PATCH_INITIAL_SYNC
|
||||
// FIXME: this method should be removed when SDK will fix the initial sync issue
|
||||
#pragma mark - KVO
|
||||
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
|
||||
{
|
||||
if ([@"isInitialSyncDone" isEqualToString:keyPath])
|
||||
{
|
||||
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
|
||||
if ([@"isInitialSyncDone" isEqualToString:keyPath]) {
|
||||
MatrixHandler *mxHandler = [MatrixHandler sharedHandler];
|
||||
if ([mxHandler isInitialSyncDone]) {
|
||||
[_activityIndicator stopAnimating];
|
||||
@@ -259,7 +267,7 @@ NSString *const kFailedEventId = @"failedEventId";
|
||||
// gestureRecognizer should begin only if tap is outside members list
|
||||
return !CGRectContainsPoint(frame, [gestureRecognizer locationInView:self.membersView]);
|
||||
}
|
||||
return NO;
|
||||
return YES;
|
||||
}
|
||||
|
||||
#pragma mark - Internal methods
|
||||
@@ -448,6 +456,8 @@ NSString *const kFailedEventId = @"failedEventId";
|
||||
}
|
||||
}
|
||||
|
||||
# pragma mark - Room members
|
||||
|
||||
- (void)showHideRoomMembers:(id)sender {
|
||||
// Check whether the members list is displayed
|
||||
if (members) {
|
||||
@@ -571,7 +581,119 @@ NSString *const kFailedEventId = @"failedEventId";
|
||||
members = nil;
|
||||
}
|
||||
|
||||
#pragma mark - keyboard handling
|
||||
# pragma mark - Attachment handling
|
||||
|
||||
- (void)showAttachmentView:(UIGestureRecognizer *)gestureRecognizer {
|
||||
CustomImageView *attachment = (CustomImageView*)gestureRecognizer.view;
|
||||
|
||||
// Retrieve attachment information
|
||||
NSDictionary *content = attachment.mediaInfo;
|
||||
NSString *msgtype = content[@"msgtype"];
|
||||
if ([msgtype isEqualToString:kMXMessageTypeImage]) {
|
||||
NSString *url =content[@"url"];
|
||||
if (url.length) {
|
||||
highResImage = [[CustomImageView alloc] initWithFrame:self.membersView.frame];
|
||||
highResImage.contentMode = UIViewContentModeScaleAspectFit;
|
||||
highResImage.backgroundColor = [UIColor blackColor];
|
||||
highResImage.imageURL = url;
|
||||
[self.view addSubview:highResImage];
|
||||
|
||||
// Add tap recognizer to hide attachment
|
||||
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(hideAttachmentView)];
|
||||
[tap setNumberOfTouchesRequired:1];
|
||||
[tap setNumberOfTapsRequired:1];
|
||||
[highResImage addGestureRecognizer:tap];
|
||||
highResImage.userInteractionEnabled = YES;
|
||||
}
|
||||
} else if ([msgtype isEqualToString:kMXMessageTypeVideo]) {
|
||||
NSString *url =content[@"url"];
|
||||
if (url.length) {
|
||||
NSString *mimetype = nil;
|
||||
if (content[@"info"]) {
|
||||
mimetype = content[@"info"][@"mimetype"];
|
||||
}
|
||||
AVAudioSessionCategory = [[AVAudioSession sharedInstance] category];
|
||||
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
|
||||
videoPlayer = [[MPMoviePlayerController alloc] init];
|
||||
if (videoPlayer != nil) {
|
||||
videoPlayer.scalingMode = MPMovieScalingModeAspectFit;
|
||||
[self.view addSubview:videoPlayer.view];
|
||||
[videoPlayer setFullscreen:YES animated:NO];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(moviePlayerPlaybackDidFinishNotification:)
|
||||
name:MPMoviePlayerPlaybackDidFinishNotification
|
||||
object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(moviePlayerWillExitFullscreen:)
|
||||
name:MPMoviePlayerWillExitFullscreenNotification
|
||||
object:videoPlayer];
|
||||
[MediaManager prepareMedia:url mimeType:mimetype success:^(NSString *cacheFilePath) {
|
||||
if (cacheFilePath) {
|
||||
if (tmpCachedAttachments == nil) {
|
||||
tmpCachedAttachments = [NSMutableArray array];
|
||||
}
|
||||
if ([tmpCachedAttachments indexOfObject:cacheFilePath]) {
|
||||
[tmpCachedAttachments addObject:cacheFilePath];
|
||||
}
|
||||
}
|
||||
videoPlayer.contentURL = [NSURL fileURLWithPath:cacheFilePath];
|
||||
[videoPlayer play];
|
||||
} failure:^(NSError *error) {
|
||||
[self hideAttachmentView];
|
||||
//Alert user
|
||||
[[AppDelegate theDelegate] showErrorAsAlert:error];
|
||||
}];
|
||||
}
|
||||
}
|
||||
} else if ([msgtype isEqualToString:kMXMessageTypeAudio]) {
|
||||
} else if ([msgtype isEqualToString:kMXMessageTypeLocation]) {
|
||||
}
|
||||
}
|
||||
|
||||
- (void)hideAttachmentView {
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:MPMoviePlayerPlaybackDidFinishNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:MPMoviePlayerWillExitFullscreenNotification object:nil];
|
||||
|
||||
if (highResImage) {
|
||||
[highResImage removeFromSuperview];
|
||||
highResImage = nil;
|
||||
}
|
||||
// Restore audio category
|
||||
if (AVAudioSessionCategory) {
|
||||
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategory error:nil];
|
||||
}
|
||||
if (videoPlayer) {
|
||||
[videoPlayer stop];
|
||||
[videoPlayer setFullscreen:NO];
|
||||
[videoPlayer.view removeFromSuperview];
|
||||
videoPlayer = nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)moviePlayerWillExitFullscreen:(NSNotification*)notification {
|
||||
if (notification.object == videoPlayer) {
|
||||
[self hideAttachmentView];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)moviePlayerPlaybackDidFinishNotification:(NSNotification *)notification {
|
||||
NSDictionary *notificationUserInfo = [notification userInfo];
|
||||
NSNumber *resultValue = [notificationUserInfo objectForKey:MPMoviePlayerPlaybackDidFinishReasonUserInfoKey];
|
||||
MPMovieFinishReason reason = [resultValue intValue];
|
||||
|
||||
// error cases
|
||||
if (reason == MPMovieFinishReasonPlaybackError) {
|
||||
NSError *mediaPlayerError = [notificationUserInfo objectForKey:@"error"];
|
||||
if (mediaPlayerError) {
|
||||
NSLog(@"Playback failed with error description: %@", [mediaPlayerError localizedDescription]);
|
||||
[self hideAttachmentView];
|
||||
//Alert user
|
||||
[[AppDelegate theDelegate] showErrorAsAlert:mediaPlayerError];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Keyboard handling
|
||||
|
||||
- (void)onKeyboardWillShow:(NSNotification *)notif {
|
||||
NSValue *rectVal = notif.userInfo[UIKeyboardFrameEndUserInfoKey];
|
||||
@@ -744,6 +866,11 @@ NSString *const kFailedEventId = @"failedEventId";
|
||||
}
|
||||
}
|
||||
|
||||
// Remove all gesture recognizer
|
||||
while (cell.attachmentView.gestureRecognizers.count) {
|
||||
[cell.attachmentView removeGestureRecognizer:cell.attachmentView.gestureRecognizers[0]];
|
||||
}
|
||||
|
||||
// Check whether the previous message has been sent by the same user.
|
||||
// We group together messages from the same user. The user's picture and name are displayed only for the first message.
|
||||
// We consider a new chunk when the user is different from the previous message's one.
|
||||
@@ -763,8 +890,10 @@ NSString *const kFailedEventId = @"failedEventId";
|
||||
cell.messageTextView.contentInset = UIEdgeInsetsZero;
|
||||
|
||||
// Set user's picture
|
||||
cell.placeholder = @"default-profile";
|
||||
cell.pictureURL = [mxRoom.state memberWithUserId:mxEvent.userId].avatarUrl;
|
||||
cell.pictureView.placeholder = @"default-profile";
|
||||
cell.pictureView.imageURL = [mxRoom.state memberWithUserId:mxEvent.userId].avatarUrl;
|
||||
[cell.pictureView.layer setCornerRadius:cell.pictureView.frame.size.width / 2];
|
||||
cell.pictureView.clipsToBounds = YES;
|
||||
} else {
|
||||
// Adjust display of other messages of the chunk
|
||||
cell.pictureView.hidden = YES;
|
||||
@@ -835,6 +964,7 @@ NSString *const kFailedEventId = @"failedEventId";
|
||||
enableLinkDetection = NO;
|
||||
}
|
||||
} else {
|
||||
// Adjust constraint constant
|
||||
cell.msgTextViewWidthConstraint.constant = contentSize.width;
|
||||
// Align attachment inside text view by considering text view edge inset
|
||||
cell.attachmentViewTopAlignmentConstraint.constant = ROOM_MESSAGE_CELL_IMAGE_MARGIN + cell.messageTextView.contentInset.top;
|
||||
@@ -850,24 +980,38 @@ NSString *const kFailedEventId = @"failedEventId";
|
||||
|
||||
NSString *msgtype = mxEvent.content[@"msgtype"];
|
||||
if ([msgtype isEqualToString:kMXMessageTypeImage] || [msgtype isEqualToString:kMXMessageTypeVideo]) {
|
||||
NSString *url = mxEvent.content[@"thumbnail_url"];
|
||||
NSString *url = nil;
|
||||
if ([msgtype isEqualToString:kMXMessageTypeVideo]) {
|
||||
cell.playIconView.hidden = NO;
|
||||
if (mxEvent.content[@"info"]) {
|
||||
url = mxEvent.content[@"info"][@"thumbnail_url"];
|
||||
}
|
||||
} else {
|
||||
url = mxEvent.content[@"thumbnail_url"];
|
||||
}
|
||||
|
||||
if (url == nil) {
|
||||
url = mxEvent.content[@"url"];
|
||||
}
|
||||
cell.attachedImageURL = url;
|
||||
cell.attachmentView.imageURL = url;
|
||||
|
||||
if ([msgtype isEqualToString:kMXMessageTypeVideo]) {
|
||||
cell.playIconView.hidden = NO;
|
||||
}
|
||||
// Add tap recognizer to open attachment
|
||||
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(showAttachmentView:)];
|
||||
[tap setNumberOfTouchesRequired:1];
|
||||
[tap setNumberOfTapsRequired:1];
|
||||
[tap setDelegate:self];
|
||||
[cell.attachmentView addGestureRecognizer:tap];
|
||||
// Store attachment content description used in showAttachmentView:
|
||||
cell.attachmentView.mediaInfo = mxEvent.content;
|
||||
} else {
|
||||
cell.attachedImageURL = nil;
|
||||
cell.attachmentView.imageURL = nil;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Text message will be displayed in textView with max width
|
||||
cell.msgTextViewWidthConstraint.constant = ROOM_MESSAGE_CELL_MAX_TEXTVIEW_WIDTH;
|
||||
// Cancel potential attachment loading
|
||||
cell.attachedImageURL = nil;
|
||||
cell.attachmentView.imageURL = nil;
|
||||
cell.attachmentView.hidden = YES;
|
||||
cell.playIconView.hidden = YES;
|
||||
|
||||
@@ -907,7 +1051,16 @@ NSString *const kFailedEventId = @"failedEventId";
|
||||
if ([msgtype isEqualToString:kMXMessageTypeImage] || [msgtype isEqualToString:kMXMessageTypeVideo]) {
|
||||
CGFloat width, height;
|
||||
width = height = 0;
|
||||
NSDictionary *thumbInfo = mxEvent.content[@"thumbnail_info"];
|
||||
|
||||
NSDictionary *thumbInfo = nil;
|
||||
if ([msgtype isEqualToString:kMXMessageTypeVideo]) {
|
||||
if (mxEvent.content[@"info"]) {
|
||||
thumbInfo = mxEvent.content[@"info"][@"thumbnail_info"];
|
||||
}
|
||||
} else {
|
||||
thumbInfo = mxEvent.content[@"thumbnail_info"];
|
||||
}
|
||||
|
||||
if (thumbInfo) {
|
||||
width = [thumbInfo[@"w"] integerValue] + 2 * ROOM_MESSAGE_CELL_IMAGE_MARGIN;
|
||||
height = [thumbInfo[@"h"] integerValue] + 2 * ROOM_MESSAGE_CELL_IMAGE_MARGIN;
|
||||
@@ -1192,7 +1345,7 @@ NSString *const kFailedEventId = @"failedEventId";
|
||||
dateFormatter = nil;
|
||||
} else {
|
||||
// dateTime will be visible
|
||||
NSString *dateFormat = @"MMM dd HH:mm";
|
||||
NSString *dateFormat = @"MMM dd HH:mm";
|
||||
dateFormatter = [[NSDateFormatter alloc] init];
|
||||
[dateFormatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:[[[NSBundle mainBundle] preferredLocalizations] objectAtIndex:0]]];
|
||||
[dateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4];
|
||||
@@ -1293,11 +1446,13 @@ NSString *const kFailedEventId = @"failedEventId";
|
||||
// We store temporarily the image in cache, use the localId to build temporary url
|
||||
NSString *dummyURL = [NSString stringWithFormat:@"%@%@", kMediaManagerPrefixForDummyURL, localEventId];
|
||||
NSData *imageData = UIImageJPEGRepresentation(image, 0.5);
|
||||
[MediaManager cachePictureWithData:imageData forURL:dummyURL];
|
||||
if (tmpCachedAttachments == nil) {
|
||||
tmpCachedAttachments = [NSMutableArray array];
|
||||
NSString *cacheFilePath = [MediaManager cacheMediaData:imageData forURL:dummyURL mimeType:@"image/jpeg"];
|
||||
if (cacheFilePath) {
|
||||
if (tmpCachedAttachments == nil) {
|
||||
tmpCachedAttachments = [NSMutableArray array];
|
||||
}
|
||||
[tmpCachedAttachments addObject:cacheFilePath];
|
||||
}
|
||||
[tmpCachedAttachments addObject:dummyURL];
|
||||
NSMutableDictionary *thumbnailInfo = [[NSMutableDictionary alloc] init];
|
||||
[thumbnailInfo setValue:@"image/jpeg" forKey:@"mimetype"];
|
||||
[thumbnailInfo setValue:[NSNumber numberWithUnsignedInteger:(NSUInteger)image.size.width] forKey:@"w"];
|
||||
@@ -1558,9 +1713,10 @@ NSString *const kFailedEventId = @"failedEventId";
|
||||
[mxHandler.mxRestClient uploadContent:thumbnailData mimeType:@"image/jpeg" timeout:30 success:^(NSString *url) {
|
||||
// Prepare content of attached video
|
||||
NSMutableDictionary *videoContent = [[NSMutableDictionary alloc] init];
|
||||
NSMutableDictionary *videoInfo = [[NSMutableDictionary alloc] init];
|
||||
[videoContent setValue:@"m.video" forKey:@"msgtype"];
|
||||
[videoContent setValue:url forKey:@"thumbnail_url"];
|
||||
[videoContent setValue:thumbnailInfo forKey:@"thumbnail_info"];
|
||||
[videoInfo setValue:url forKey:@"thumbnail_url"];
|
||||
[videoInfo setValue:thumbnailInfo forKey:@"thumbnail_info"];
|
||||
|
||||
// Convert video container to mp4
|
||||
AVURLAsset* videoAsset = [AVURLAsset URLAssetWithURL:selectedVideo options:nil];
|
||||
@@ -1575,12 +1731,12 @@ NSString *const kFailedEventId = @"failedEventId";
|
||||
NSArray *supportedFileTypes = exportSession.supportedFileTypes;
|
||||
if ([supportedFileTypes containsObject:AVFileTypeMPEG4]) {
|
||||
exportSession.outputFileType = AVFileTypeMPEG4;
|
||||
[videoContent setValue:@"video/mp4" forKey:@"mimetype"];
|
||||
[videoInfo setValue:@"video/mp4" forKey:@"mimetype"];
|
||||
} else {
|
||||
NSLog(@"Unexpected case: MPEG-4 file format is not supported");
|
||||
// we send QuickTime movie file by default
|
||||
exportSession.outputFileType = AVFileTypeQuickTimeMovie;
|
||||
[videoContent setValue:@"video/quicktime" forKey:@"mimetype"];
|
||||
[videoInfo setValue:@"video/quicktime" forKey:@"mimetype"];
|
||||
}
|
||||
// Export video file and send it
|
||||
[exportSession exportAsynchronouslyWithCompletionHandler:^{
|
||||
@@ -1593,13 +1749,13 @@ NSString *const kFailedEventId = @"failedEventId";
|
||||
nil]
|
||||
];
|
||||
|
||||
[videoContent setValue:[NSNumber numberWithDouble:(1000 * CMTimeGetSeconds(asset.duration))] forKey:@"duration"];
|
||||
[videoInfo setValue:[NSNumber numberWithDouble:(1000 * CMTimeGetSeconds(asset.duration))] forKey:@"duration"];
|
||||
NSArray *videoTracks = [asset tracksWithMediaType:AVMediaTypeVideo];
|
||||
if (videoTracks.count > 0) {
|
||||
AVAssetTrack *videoTrack = [videoTracks objectAtIndex:0];
|
||||
CGSize videoSize = videoTrack.naturalSize;
|
||||
[videoContent setValue:[NSNumber numberWithUnsignedInteger:(NSUInteger)videoSize.width] forKey:@"w"];
|
||||
[videoContent setValue:[NSNumber numberWithUnsignedInteger:(NSUInteger)videoSize.height] forKey:@"h"];
|
||||
[videoInfo setValue:[NSNumber numberWithUnsignedInteger:(NSUInteger)videoSize.width] forKey:@"w"];
|
||||
[videoInfo setValue:[NSNumber numberWithUnsignedInteger:(NSUInteger)videoSize.height] forKey:@"h"];
|
||||
}
|
||||
|
||||
// Upload the video
|
||||
@@ -1607,9 +1763,10 @@ NSString *const kFailedEventId = @"failedEventId";
|
||||
[[NSFileManager defaultManager] removeItemAtPath:[tmpVideoLocation path] error:nil];
|
||||
if (videoData) {
|
||||
if (videoData.length < UPLOAD_FILE_SIZE) {
|
||||
[videoContent setValue:[NSNumber numberWithUnsignedInteger:videoData.length] forKey:@"size"];
|
||||
[mxHandler.mxRestClient uploadContent:videoData mimeType:videoContent[@"mimetype"] timeout:30 success:^(NSString *url) {
|
||||
[videoInfo setValue:[NSNumber numberWithUnsignedInteger:videoData.length] forKey:@"size"];
|
||||
[mxHandler.mxRestClient uploadContent:videoData mimeType:videoInfo[@"mimetype"] timeout:30 success:^(NSString *url) {
|
||||
[videoContent setValue:url forKey:@"url"];
|
||||
[videoContent setValue:videoInfo forKey:@"info"];
|
||||
[videoContent setValue:@"Video" forKey:@"body"];
|
||||
[self postMessage:videoContent withLocalEventId:localEventId];
|
||||
} failure:^(NSError *error) {
|
||||
|
||||
Reference in New Issue
Block a user