message: Fix problem with constraints

diff:
<?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="11762" systemVersion="16C67" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="12121" systemVersion="16F73" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
- <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11757"/>
+ <deployment identifier="iOS"/>
+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<rect key="frame" x="0.0" y="0.0" width="600" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="aCf-VI-ocb" id="Eg5-vl-rni">
- <rect key="frame" x="0.0" y="0.0" width="600" height="43"/>
+ <rect key="frame" x="0.0" y="0.0" width="600" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="9dA-E8-w3v">
</subviews>
<constraints>
<constraint firstItem="9dA-E8-w3v" firstAttribute="centerY" secondItem="Eg5-vl-rni" secondAttribute="centerY" id="HHv-PY-RDK"/>
- <constraint firstAttribute="bottomMargin" secondItem="Xx4-AP-OQs" secondAttribute="bottom" constant="3.5" id="Ikz-iJ-l4h"/>
- <constraint firstItem="Xx4-AP-OQs" firstAttribute="centerY" secondItem="Eg5-vl-rni" secondAttribute="centerY" id="Uky-gM-6WY"/>
+ <constraint firstAttribute="bottomMargin" secondItem="Xx4-AP-OQs" secondAttribute="bottom" constant="3" id="Ikz-iJ-l4h"/>
<constraint firstItem="Xx4-AP-OQs" firstAttribute="top" secondItem="Eg5-vl-rni" secondAttribute="topMargin" constant="3" id="Vem-3Z-NyP"/>
<constraint firstItem="Xx4-AP-OQs" firstAttribute="leading" secondItem="Eg5-vl-rni" secondAttribute="leading" constant="8" id="Wih-ke-1dd"/>
<constraint firstItem="9dA-E8-w3v" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="Xx4-AP-OQs" secondAttribute="trailing" constant="8" id="hms-8a-BYd"/>

original_message: Fix problem with constraints


message: Add prepareForReuse method to cell with button

change_type: MODIFY

diff:
@implementation MXKTableViewCellWithButton
-@end
+- (void)prepareForReuse
+{
+ [super prepareForReuse];
+
+ self.mxkButton.titleLabel.text = nil;
+}
+@end

license: Apache License 2.0

repo: matrix-org/matrix-ios-kit


message: Add new setting for CallKit

diff:
*/
@property (nonatomic) UIColor *presenceColorForOfflineUser;
+#pragma mark - Calls
+
+/**
+ Return YES if the user enable CallKit support.
+
+ This boolean value is defined in shared settings object with the key: `enableCallKit`.
+ Return YES if no value is defined.
+ */
+@property (nonatomic, getter=isCallKitEnabled) BOOL enableCallKit;
#pragma mark - Class methods

diff:
@@ -31,6 +31,7 @@ static MXKAppSettings *standardAppSettings = nil;
@synthesize showLeftMembersInRoomMemberList, sortRoomMembersUsingLastSeenTime;
@synthesize syncLocalContacts, syncLocalContactsPermissionRequested, phonebookCountryCode;
@synthesize presenceColorForOnlineUser, presenceColorForUnavailableUser, presenceColorForOfflineUser;
+@synthesize enableCallKit;
+ (MXKAppSettings *)standardAppSettings
{
@@ -64,6 +65,8 @@ static MXKAppSettings *standardAppSettings = nil;
httpLinkScheme = @"http";
httpsLinkScheme = @"https";
+
+ enableCallKit = YES;
}
return self;
}
@@ -95,6 +98,8 @@ static MXKAppSettings *standardAppSettings = nil;
[[NSUserDefaults standardUserDefaults] removeObjectForKey:@"httpLinkScheme"];
[[NSUserDefaults standardUserDefaults] removeObjectForKey:@"httpsLinkScheme"];
+ [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"enableCallKit"];
+
[[NSUserDefaults standardUserDefaults] synchronize];
}
else
@@ -116,6 +121,8 @@ static MXKAppSettings *standardAppSettings = nil;
httpLinkScheme = @"http";
httpsLinkScheme = @"https";
+
+ enableCallKit = YES;
}
}
@@ -576,4 +583,38 @@ static MXKAppSettings *standardAppSettings = nil;
}
}
+#pragma mark - Calls
+
+- (BOOL)isCallKitEnabled
+{
+ if (self == [MXKAppSettings standardAppSettings])
+ {
+ id storedValue = [[NSUserDefaults standardUserDefaults] objectForKey:@"enableCallKit"];
+ if (storedValue)
+ {
+ return [(NSNumber *)storedValue boolValue];
+ }
+ else
+ {
+ return YES;
+ }
+ }
+ else
+ {
+ return enableCallKit;
+ }
+}
+
+- (void)setEnableCallKit:(BOOL)enable
+{
+ if (self == [MXKAppSettings standardAppSettings])
+ {
+ [[NSUserDefaults standardUserDefaults] setBool:enable forKey:@"enableCallKit"];
+ }
+ else
+ {
+ enableCallKit = enable;
+ }
+}
+
@end

original_message: Add new setting for CallKit


message: Add missed nonatomic attributes to properties

diff:
@@ -24,8 +24,6 @@ typedef NS_ENUM(NSInteger, PhotoBrowserAnimationType) {
@protocol MXKSourceAttachmentAnimatorDelegate <NSObject>
-@required
-
- (UIImageView *)originalImageView;
- (CGRect)convertedFrameForOriginalImageView;
@@ -34,8 +32,6 @@ typedef NS_ENUM(NSInteger, PhotoBrowserAnimationType) {
@protocol MXKDestinationAttachmentAnimatorDelegate <NSObject>
-@required
-
- (UIImageView *)finalImageView;
@end

diff:
@interface MXKAttachmentAnimator ()
-@property PhotoBrowserAnimationType animationType;
-@property (weak) UIViewController <MXKSourceAttachmentAnimatorDelegate> *sourceViewController;
+@property (nonatomic) PhotoBrowserAnimationType animationType;
+@property (nonatomic, weak) UIViewController <MXKSourceAttachmentAnimatorDelegate> *sourceViewController;
@end

diff:
@interface MXKAttachmentInteractionController : UIPercentDrivenInteractiveTransition
-@property BOOL interactionInProgress;
+@property (nonatomic) BOOL interactionInProgress;
- (instancetype)initWithDestinationViewController:(UIViewController <MXKDestinationAttachmentAnimatorDelegate> *)viewController sourceViewController:(UIViewController <MXKSourceAttachmentAnimatorDelegate> *)sourceViewController;

diff:
@interface MXKAttachmentInteractionController ()
-@property (weak) UIViewController <MXKDestinationAttachmentAnimatorDelegate> *destinationViewController;
-@property (weak) UIViewController <MXKSourceAttachmentAnimatorDelegate> *sourceViewController;
+@property (nonatomic, weak) UIViewController <MXKDestinationAttachmentAnimatorDelegate> *destinationViewController;
+@property (nonatomic, weak) UIViewController <MXKSourceAttachmentAnimatorDelegate> *sourceViewController;
-@property UIImageView *transitioningImageView;
-@property id <UIViewControllerContextTransitioning> transitionContext;
+@property (nonatomic) UIImageView *transitioningImageView;
+@property (nonatomic) id <UIViewControllerContextTransitioning> transitionContext;
-@property CGPoint translation;
-@property CGPoint delta;
+@property (nonatomic) CGPoint translation;
+@property (nonatomic) CGPoint delta;
@end

diff:
}
//animations
-@property MXKAttachmentInteractionController *interactionController;
+@property (nonatomic) MXKAttachmentInteractionController *interactionController;
-@property UIViewController <MXKSourceAttachmentAnimatorDelegate> *sourceViewController;
+@property (nonatomic) UIViewController <MXKSourceAttachmentAnimatorDelegate> *sourceViewController;
-@property UIImageView *originalImageView;
-@property CGRect convertedFrame;
+@property (nonatomic) UIImageView *originalImageView;
+@property (nonatomic) CGRect convertedFrame;
-@property BOOL customAnimationsEnabled;
+@property (nonatomic) BOOL customAnimationsEnabled;
@end

diff:
@@ -148,14 +148,14 @@ NSString *const kCmdChangeRoomTopic = @"/topic";
/**
The eventId of the Attachment that was used to open the Attachments ViewController
*/
-@property NSString *openedAttachmentEventId;
+@property (nonatomic) NSString *openedAttachmentEventId;
/**
The eventId of the Attachment from which the Attachments ViewController was closed
*/
-@property NSString *closedAttachmentEventId;
+@property (nonatomic) NSString *closedAttachmentEventId;
-@property UIImageView *openedAttachmentImageView;
+@property (nonatomic) UIImageView *openedAttachmentImageView;
@end


message: Add MXKSoundPlayer

diff:
71DE22E71BCE3FF200284153 /* MXKRoomBubbleCellDataWithIncomingAppendingMode.m in Sources */ = {isa = PBXBuildFile; fileRef = 71DE22E51BCE3FF200284153 /* MXKRoomBubbleCellDataWithIncomingAppendingMode.m */; };
71EBE6631C04608100E7D953 /* MXKRoomActivitiesView.m in Sources */ = {isa = PBXBuildFile; fileRef = 71EBE6621C04608100E7D953 /* MXKRoomActivitiesView.m */; };
79FA5AB121247287B85FA151 /* libPods-MatrixKitTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9F0ED791C0728768E176BE57 /* libPods-MatrixKitTests.a */; };
+ 92663A6C1EF6E5B3005FB712 /* MXKSoundPlayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 92663A6B1EF6E5B3005FB712 /* MXKSoundPlayer.m */; };
ACD9DAA6B4DCFC7E33E12A97 /* libPods-MatrixKitSample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 665BACA3D253B4407B1C4FD7 /* libPods-MatrixKitSample.a */; };
CE14CA661E80122600E329A3 /* MXKAttachmentAnimator.m in Sources */ = {isa = PBXBuildFile; fileRef = CE14CA631E80122600E329A3 /* MXKAttachmentAnimator.m */; };
CE14CA671E80122600E329A3 /* MXKAttachmentInteractionController.m in Sources */ = {isa = PBXBuildFile; fileRef = CE14CA651E80122600E329A3 /* MXKAttachmentInteractionController.m */; };
71EBE6611C04608100E7D953 /* MXKRoomActivitiesView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MXKRoomActivitiesView.h; sourceTree = "<group>"; };
71EBE6621C04608100E7D953 /* MXKRoomActivitiesView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MXKRoomActivitiesView.m; sourceTree = "<group>"; };
8C751E43C4D87B309065E3C8 /* Pods-MatrixKitTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MatrixKitTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-MatrixKitTests/Pods-MatrixKitTests.release.xcconfig"; sourceTree = "<group>"; };
+ 92663A6A1EF6E5B3005FB712 /* MXKSoundPlayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MXKSoundPlayer.h; sourceTree = "<group>"; };
+ 92663A6B1EF6E5B3005FB712 /* MXKSoundPlayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MXKSoundPlayer.m; sourceTree = "<group>"; };
9F0ED791C0728768E176BE57 /* libPods-MatrixKitTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-MatrixKitTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
BFDF88630F521F8C5854F64F /* Pods-MatrixKitTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MatrixKitTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-MatrixKitTests/Pods-MatrixKitTests.debug.xcconfig"; sourceTree = "<group>"; };
C1C97E32A7F1D6C4B99A47EF /* Pods-MatrixKitSample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MatrixKitSample.debug.xcconfig"; path = "Pods/Target Support Files/Pods-MatrixKitSample/Pods-MatrixKitSample.debug.xcconfig"; sourceTree = "<group>"; };
F0F148C41AB31240005F5D4A /* MXKTools.h */,
F0F148C51AB31240005F5D4A /* MXKTools.m */,
F0F535BC1ACD748E00B603F8 /* MXKResponderRageShaking.h */,
+ 92663A6A1EF6E5B3005FB712 /* MXKSoundPlayer.h */,
+ 92663A6B1EF6E5B3005FB712 /* MXKSoundPlayer.m */,
);
path = Utils;
sourceTree = "<group>";
F01449AD1B53FA7600EA7D73 /* MXKPushRuleCreationTableViewCell.m in Sources */,
3235CD771C32DC8A0084EA40 /* MXKSearchDataSource.m in Sources */,
F0CF98DD1B0B7FDC00EAE373 /* MXKTableViewCellWithLabelAndSubLabel.m in Sources */,
+ 92663A6C1EF6E5B3005FB712 /* MXKSoundPlayer.m in Sources */,
F00FA85D1C0867F900E25826 /* MXKRoomIncomingAttachmentWithoutSenderInfoBubbleCell.m in Sources */,
F02D21491B7109950002DE01 /* MXKConstants.m in Sources */,
F07E18101ABC2EDA00DE3766 /* MXKRoomDataSource.m in Sources */,

change_type: ADD

diff:
+/*
+ Copyright 2017 Vector Creations 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/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface MXKSoundPlayer : NSObject
+
++ (instancetype)sharedInstance;
+
++ (instancetype)init NS_UNAVAILABLE;
++ (instancetype)new NS_UNAVAILABLE;
+
+- (void)playSoundAt:(NSURL *)url repeat:(BOOL)repeat vibrate:(BOOL)vibrate routeToBuiltInReciever:(BOOL)useBuiltInReciever;
+- (void)stopPlaying;
+
+- (void)vibrateWithRepeat:(BOOL)repeat;
+- (void)stopVibrating;
+
+@end
+
+NS_ASSUME_NONNULL_END

diff:
+/*
+ Copyright 2017 Vector Creations 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 "MXKSoundPlayer.h"
+
+#import <AVFoundation/AVFAudio.h>
+#import <AudioToolbox/AudioServices.h>
+
+static const NSTimeInterval kVibrationInterval = 1.24875;
+
+@interface MXKSoundPlayer () <AVAudioPlayerDelegate>
+
+@property (nonatomic, nullable) AVAudioPlayer *audioPlayer;
+
+@property (nonatomic, getter=isVibrating) BOOL vibrating;
+
+@end
+
+@implementation MXKSoundPlayer
+
++ (instancetype)sharedInstance
+{
+ static MXKSoundPlayer *soundPlayer;
+ static dispatch_once_t onceToken;
+ dispatch_once(&onceToken, ^{
+ soundPlayer = [MXKSoundPlayer alloc];
+ });
+ return soundPlayer;
+}
+
+- (void)playSoundAt:(NSURL *)url repeat:(BOOL)repeat vibrate:(BOOL)vibrate routeToBuiltInReciever:(BOOL)useBuiltInReciever
+{
+ if (self.audioPlayer)
+ {
+ [self stopPlaying];
+ }
+
+ self.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
+
+ if (!self.audioPlayer)
+ return;
+
+ self.audioPlayer.delegate = self;
+ self.audioPlayer.numberOfLoops = repeat ? -1 : 0;
+ [self.audioPlayer prepareToPlay];
+
+ // Setup AVAudioSession
+ // We use SoloAmbient instead of Playback category to respect silent mode
+ NSString *audioSessionCategory = useBuiltInReciever ? AVAudioSessionCategoryPlayAndRecord : AVAudioSessionCategorySoloAmbient;
+ [[AVAudioSession sharedInstance] setCategory:audioSessionCategory error:nil];
+
+ if (vibrate)
+ [self vibrateWithRepeat:repeat];
+
+ [self.audioPlayer play];
+}
+
+- (void)stopPlaying
+{
+ if (self.audioPlayer)
+ {
+ [self.audioPlayer stop];
+ self.audioPlayer = nil;
+
+ // Release the audio session to allow resuming of background music app
+ [[AVAudioSession sharedInstance] setActive:NO withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:nil];
+ }
+
+ if (self.isVibrating)
+ {
+ [self stopVibrating];
+ }
+}
+
+- (void)vibrateWithRepeat:(BOOL)repeat
+{
+ self.vibrating = YES;
+
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(kVibrationInterval * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
+ AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
+
+ NSNumber *objRepeat = @(repeat);
+ AudioServicesAddSystemSoundCompletion(kSystemSoundID_Vibrate,
+ NULL,
+ kCFRunLoopCommonModes,
+ vibrationCompleted,
+ (__bridge_retained void * _Nullable)(objRepeat));
+ });
+}
+
+- (void)stopVibrating
+{
+ self.vibrating = NO;
+ AudioServicesRemoveSystemSoundCompletion(kSystemSoundID_Vibrate);
+}
+
+void vibrationCompleted(SystemSoundID ssID, void* __nullable clientData)
+{
+ NSNumber *objRepeat = (__bridge NSNumber *)clientData;
+ BOOL repeat = [objRepeat boolValue];
+ CFRelease(clientData);
+
+ MXKSoundPlayer *soundPlayer = [MXKSoundPlayer sharedInstance];
+
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(kVibrationInterval * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
+ if (repeat && soundPlayer.isVibrating)
+ {
+ [soundPlayer vibrateWithRepeat:repeat];
+ }
+ else
+ {
+ [soundPlayer stopVibrating];
+ }
+ });
+}
+
+#pragma mark - AVAudioPlayerDelegate
+
+// This method is called only when the end of the player's track is reached.
+// If you call `stop` or `pause` on player this method won't be called
+- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
+{
+ self.audioPlayer = nil;
+
+ // Release the audio session to allow resuming of background music app
+ [[AVAudioSession sharedInstance] setActive:NO withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:nil];
+}
+
+@end

original_message: Add MXKSoundPlayer


message: Update method calls

diff:
@@ -401,7 +401,7 @@ NSString *const kMXKCallViewControllerBackToAppNotification = @"kMXKCallViewCont
audioUrl = [self audioURLWithName:@"ringback"];
}
- [[MXKSoundPlayer sharedInstance] playSoundAt:audioUrl repeat:YES vibrate:mxCall.isIncoming routeToBuiltInReciever:!mxCall.isIncoming];
+ [[MXKSoundPlayer sharedInstance] playSoundAt:audioUrl repeat:YES vibrate:mxCall.isIncoming routeToBuiltInReceiver:!mxCall.isIncoming];
}
else
{
@@ -586,7 +586,7 @@ NSString *const kMXKCallViewControllerBackToAppNotification = @"kMXKCallViewCont
if (soundName)
{
NSURL *audioUrl = [self audioURLWithName:soundName];
- [[MXKSoundPlayer sharedInstance] playSoundAt:audioUrl repeat:NO vibrate:NO routeToBuiltInReciever:YES];
+ [[MXKSoundPlayer sharedInstance] playSoundAt:audioUrl repeat:NO vibrate:NO routeToBuiltInReceiver:YES];
}
else
{

original_message: Update method calls


message: Make creation methods of MXKCallViewController to be generic

diff:
@@ -78,14 +78,14 @@ NSString *const kMXKCallViewControllerBackToAppNotification = @"kMXKCallViewCont
+ (UINib *)nib
{
- return [UINib nibWithNibName:NSStringFromClass([MXKCallViewController class])
- bundle:[NSBundle bundleForClass:[MXKCallViewController class]]];
+ return [UINib nibWithNibName:NSStringFromClass(self.class)
+ bundle:[NSBundle bundleForClass:self.class]];
}
+ (instancetype)callViewController:(MXCall*)call
{
- MXKCallViewController* instance = [[[self class] alloc] initWithNibName:NSStringFromClass([MXKCallViewController class])
- bundle:[NSBundle bundleForClass:[MXKCallViewController class]]];
+ MXKCallViewController *instance = [[[self class] alloc] initWithNibName:NSStringFromClass(self.class)
+ bundle:[NSBundle bundleForClass:self.class]];
// Load the view controller's view now (buttons and views will then be available).
if ([instance respondsToSelector:@selector(loadViewIfNeeded)])


message: Add playRingtone property

diff:
@@ -109,6 +109,14 @@ extern NSString *const kMXKCallViewControllerBackToAppNotification;
*/
@property (nonatomic, weak) id<MXKCallViewControllerDelegate> delegate;
+/*
+ Specifies whether a ringtone must be played on incoming call.
+ It's important to set this value before you will set `mxCall` otherwise value of this property can has no effect.
+
+ Defaults to YES.
+ */
+@property (nonatomic) BOOL playRingtone;
+
#pragma mark - Class methods
/**

diff:
@@ -101,6 +101,8 @@ NSString *const kMXKCallViewControllerBackToAppNotification = @"kMXKCallViewCont
- (void)finalizeInit
{
[super finalizeInit];
+
+ _playRingtone = YES;
}
- (void)viewDidLoad
@@ -394,6 +396,7 @@ NSString *const kMXKCallViewControllerBackToAppNotification = @"kMXKCallViewCont
NSURL *audioUrl;
if (mxCall.isIncoming)
{
+ if (self.playRingtone)
audioUrl = [self audioURLWithName:@"ring"];
}
else
@@ -401,8 +404,11 @@ NSString *const kMXKCallViewControllerBackToAppNotification = @"kMXKCallViewCont
audioUrl = [self audioURLWithName:@"ringback"];
}
+ if (audioUrl)
+ {
[[MXKSoundPlayer sharedInstance] playSoundAt:audioUrl repeat:YES vibrate:mxCall.isIncoming routeToBuiltInReceiver:!mxCall.isIncoming];
}
+ }
else
{
[[MXKSoundPlayer sharedInstance] stopPlaying];

original_message: Add playRingtone property


message: Remove AVAudioSession deactivation from stopPlaying method

diff:
@@ -74,9 +74,6 @@ static const NSTimeInterval kVibrationInterval = 1.24875;
{
[self.audioPlayer stop];
self.audioPlayer = nil;
-
- // Release the audio session to allow resuming of background music app
- [[AVAudioSession sharedInstance] setActive:NO withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:nil];
}
if (self.isVibrating)


message: Fix sound problems

diff:
#import "MXKCallViewController.h"
+#import <MatrixSDK/MXCallKitAdapter.h>
+
#import "MXKAlert.h"
+#import "MXKAppSettings.h"
#import "MXMediaManager.h"
#import "MXKSoundPlayer.h"
#import "MXKTools.h"
@@ -136,6 +139,16 @@ NSString *const kMXKCallViewControllerBackToAppNotification = @"kMXKCallViewCont
// Refresh call information
self.mxCall = mxCall;
+
+ // Listen to AVAudioSession activation notification if CallKit is available and enabled
+ BOOL isCallKitAvailable = [MXCallKitAdapter callKitAvailable] && [MXKAppSettings standardAppSettings].isCallKitEnabled;
+ if (isCallKitAvailable)
+ {
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(handleAudioSessionActivationNotification)
+ name:kMXCallKitAdapterAudioSessionDidActive
+ object:nil];
+ }
}
- (void)didReceiveMemoryWarning
@@ -145,6 +158,7 @@ NSString *const kMXKCallViewControllerBackToAppNotification = @"kMXKCallViewCont
- (void)dealloc
{
+ [[NSNotificationCenter defaultCenter] removeObserver:self name:kMXCallKitAdapterAudioSessionDidActive object:nil];
}
- (void)viewWillAppear:(BOOL)animated
@@ -533,9 +547,16 @@ NSString *const kMXKCallViewControllerBackToAppNotification = @"kMXKCallViewCont
[localPreviewActivityView startAnimating];
break;
case MXCallStateCreateOffer:
+ {
+ BOOL isCallKitAvailable = [MXCallKitAdapter callKitAvailable] && [MXKAppSettings standardAppSettings].isCallKitEnabled;
+ if (!isCallKitAvailable)
+ {
self.isRinging = YES;
+ }
+
callStatusLabel.text = [NSBundle mxk_localizedStringForKey:@"call_ring"];
break;
+ }
case MXCallStateRinging:
self.isRinging = YES;
if (call.isVideoCall)
@@ -597,6 +618,9 @@ NSString *const kMXKCallViewControllerBackToAppNotification = @"kMXKCallViewCont
else
{
[[MXKSoundPlayer sharedInstance] stopPlaying];
+
+ // Release the audio session to allow resuming of background music app
+ [[AVAudioSession sharedInstance] setActive:NO withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:nil];
}
// Except in case of call error, quit the screen right now
@@ -728,6 +752,15 @@ NSString *const kMXKCallViewControllerBackToAppNotification = @"kMXKCallViewCont
return nil;
}
+- (void)handleAudioSessionActivationNotification
+{
+ // It's only relevant for outgoing calls which aren't in connected state
+ if (self.mxCall.state >= MXCallStateCreateOffer && self.mxCall.state != MXCallStateConnected && self.mxCall.state != MXCallStateEnded)
+ {
+ self.isRinging = YES;
+ }
+}
+
#pragma mark - UI methods
- (void)updateLocalPreviewLayout

original_message: Fix sound problems


message: Add parameter to stopPlaying method

diff:
@@ -425,7 +425,7 @@ NSString *const kMXKCallViewControllerBackToAppNotification = @"kMXKCallViewCont
}
else
{
- [[MXKSoundPlayer sharedInstance] stopPlaying];
+ [[MXKSoundPlayer sharedInstance] stopPlayingWithAudioSessionDeactivation:NO];
}
_isRinging = isRinging;
@@ -548,6 +548,10 @@ NSString *const kMXKCallViewControllerBackToAppNotification = @"kMXKCallViewCont
break;
case MXCallStateCreateOffer:
{
+ // When CallKit is enabled and we have an outgoing call, we need to start playing ringback sound
+ // only after AVAudioSession will be activated by the system otherwise the sound will be gone.
+ // We always receive signal about MXCallStateCreateOffer earlier than the system activates AVAudioSession
+ // so we start playing ringback sound only on AVAudioSession activation in handleAudioSessionActivationNotification
BOOL isCallKitAvailable = [MXCallKitAdapter callKitAvailable] && [MXKAppSettings standardAppSettings].isCallKitEnabled;
if (!isCallKitAvailable)
{
@@ -617,10 +621,7 @@ NSString *const kMXKCallViewControllerBackToAppNotification = @"kMXKCallViewCont
}
else
{
- [[MXKSoundPlayer sharedInstance] stopPlaying];
-
- // Release the audio session to allow resuming of background music app
- [[AVAudioSession sharedInstance] setActive:NO withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:nil];
+ [[MXKSoundPlayer sharedInstance] stopPlayingWithAudioSessionDeactivation:YES];
}
// Except in case of call error, quit the screen right now

diff:
@@ -26,7 +26,7 @@ NS_ASSUME_NONNULL_BEGIN
+ (instancetype)new NS_UNAVAILABLE;
- (void)playSoundAt:(NSURL *)url repeat:(BOOL)repeat vibrate:(BOOL)vibrate routeToBuiltInReceiver:(BOOL)useBuiltInReceiver;
-- (void)stopPlaying;
+- (void)stopPlayingWithAudioSessionDeactivation:(BOOL)deactivateAudioSession;
- (void)vibrateWithRepeat:(BOOL)repeat;
- (void)stopVibrating;

diff:
@@ -45,7 +45,7 @@ static const NSTimeInterval kVibrationInterval = 1.24875;
{
if (self.audioPlayer)
{
- [self stopPlaying];
+ [self stopPlayingWithAudioSessionDeactivation:NO];
}
self.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
@@ -68,12 +68,18 @@ static const NSTimeInterval kVibrationInterval = 1.24875;
[self.audioPlayer play];
}
-- (void)stopPlaying
+- (void)stopPlayingWithAudioSessionDeactivation:(BOOL)deactivateAudioSession;
{
if (self.audioPlayer)
{
[self.audioPlayer stop];
self.audioPlayer = nil;
+
+ if (deactivateAudioSession)
+ {
+ // Release the audio session to allow resuming of background music app
+ [[AVAudioSession sharedInstance] setActive:NO withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:nil];
+ }
}
if (self.isVibrating)

original_message: Add parameter to stopPlaying method


message: Fix problem with dismissing of MXCallViewController

diff:
@@ -595,7 +595,7 @@ NSString *const kMXKCallViewControllerBackToAppNotification = @"kMXKCallViewCont
// Except in case of call error, quit the screen right now
if (!errorAlert)
{
- [errorAlert dismissViewControllerAnimated:NO completion:nil];
+ [self dismiss];
}
break;


message: Change order of capturing weakSelf in alert's action handler

diff:
@@ -628,9 +628,9 @@ NSString *const kMXKCallViewControllerBackToAppNotification = @"kMXKCallViewCont
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
- if (weakSelf)
- {
typeof(self) self = weakSelf;
+ if (self)
+ {
self->errorAlert = nil;
[self dismiss];


message: Add showDecryptedContentInNotifications property to MXKAccount

diff:
@@ -167,6 +167,12 @@ typedef BOOL (^MXKAccountOnCertificateChange)(MXKAccount *mxAccount, NSData *cer
*/
@property (nonatomic,getter=isWarnedAboutEncryption) BOOL warnedAboutEncryption;
+/**
+ Flag indicating whether to show decrypted content in notifications.
+ NO by default
+ */
+@property (nonatomic) BOOL showDecryptedContentInNotifications;
+
/**
Register the MXKAccountOnCertificateChange block that will be used to handle certificate change during account use.
This block is nil by default, any new certificate is ignored/untrusted (this will abort the connection to the server).

diff:
@@ -196,6 +196,8 @@ static MXKAccountOnCertificateChange _onCertificateChangeBlock;
_warnedAboutEncryption = [coder decodeBoolForKey:@"warnedAboutEncryption"];
+ _showDecryptedContentInNotifications = [coder decodeBoolForKey:@"showDecryptedContentInNotifications"];
+
// Refresh device information
[self loadDeviceInformation:nil failure:nil];
}
@@ -245,6 +247,8 @@ static MXKAccountOnCertificateChange _onCertificateChangeBlock;
[coder encodeBool:_disabled forKey:@"disabled"];
[coder encodeBool:_warnedAboutEncryption forKey:@"warnedAboutEncryption"];
+
+ [coder encodeBool:_showDecryptedContentInNotifications forKey:@"showDecryptedContentInNotifications"];
}
#pragma mark - Properties


message: Add archivation

diff:
@@ -430,6 +430,14 @@ static MXKAccountOnCertificateChange _onCertificateChangeBlock;
[[MXKAccountManager sharedManager] saveAccounts];
}
+- (void)setShowDecryptedContentInNotifications:(BOOL)showDecryptedContentInNotifications
+{
+ _showDecryptedContentInNotifications = showDecryptedContentInNotifications;
+
+ // Archive updated field
+ [[MXKAccountManager sharedManager] saveAccounts];
+}
+
#pragma mark - Matrix user's profile
- (void)setUserDisplayName:(NSString*)displayname success:(void (^)())success failure:(void (^)(NSError *error))failure

original_message: Add archivation


message: Add support for incoming calls view

diff:
@@ -163,6 +163,16 @@ extern NSString *const kMXKCallViewControllerBackToAppNotification;
*/
- (void)updateProximityAndSleep;
+/**
+ Return a view that is used for informing about incoming call.
+
+ @return a view that stands for informing about incoming call or nil
+
+ @discussion Subclasses must override this method to provide appropriate for their app view.
+ When this method is called peer and mxCall are valid so you can use them.
+ */
+- (UIView *)createIncomingCallView;
+
/**
Action registered on the event 'UIControlEventTouchUpInside' for each UIButton instance.
*/

diff:
@@ -54,6 +54,8 @@ NSString *const kMXKCallViewControllerBackToAppNotification = @"kMXKCallViewCont
@property (nonatomic, assign) Boolean isRinging;
+@property (nonatomic, nullable) UIView *incomingCallView;
+
@end
@implementation MXKCallViewController
@@ -524,6 +526,54 @@ NSString *const kMXKCallViewControllerBackToAppNotification = @"kMXKCallViewCont
case MXCallStateWaitLocalMedia:
self.isRinging = NO;
[localPreviewActivityView startAnimating];
+
+ // Try to show a special view for incoming view
+ if (call.isIncoming && !self.incomingCallView)
+ {
+ UIView *incomingCallView = [self createIncomingCallView];
+ if (incomingCallView)
+ {
+ self.incomingCallView = incomingCallView;
+ [self.view addSubview:incomingCallView];
+
+ incomingCallView.translatesAutoresizingMaskIntoConstraints = NO;
+
+ [NSLayoutConstraint activateConstraints:@[
+ [NSLayoutConstraint constraintWithItem:incomingCallView
+ attribute:NSLayoutAttributeTop
+ relatedBy:NSLayoutRelationEqual
+ toItem:self.view
+ attribute:NSLayoutAttributeTop
+ multiplier:1.0
+ constant:0.0],
+
+ [NSLayoutConstraint constraintWithItem:incomingCallView
+ attribute:NSLayoutAttributeLeading
+ relatedBy:NSLayoutRelationEqual
+ toItem:self.view
+ attribute:NSLayoutAttributeLeading
+ multiplier:1.0
+ constant:0.0],
+
+ [NSLayoutConstraint constraintWithItem:incomingCallView
+ attribute:NSLayoutAttributeBottom
+ relatedBy:NSLayoutRelationEqual
+ toItem:self.view
+ attribute:NSLayoutAttributeBottom
+ multiplier:1.0
+ constant:0.0],
+
+ [NSLayoutConstraint constraintWithItem:incomingCallView
+ attribute:NSLayoutAttributeTrailing
+ relatedBy:NSLayoutRelationEqual
+ toItem:self.view
+ attribute:NSLayoutAttributeTrailing
+ multiplier:1.0
+ constant:0.0]
+ ]];
+ }
+ }
+
break;
case MXCallStateCreateOffer:
self.isRinging = YES;
@@ -547,6 +597,21 @@ NSString *const kMXKCallViewControllerBackToAppNotification = @"kMXKCallViewCont
case MXCallStateConnecting:
self.isRinging = NO;
callStatusLabel.text = [NSBundle mxk_localizedStringForKey:@"call_connecting"];
+
+ // User has accepted the call and we can remove incomingCallView
+ if (self.incomingCallView)
+ {
+ [UIView transitionWithView:self.view
+ duration:0.33
+ options:UIViewAnimationOptionTransitionCrossDissolve | UIViewAnimationOptionCurveEaseOut
+ animations:^{
+ [self.incomingCallView removeFromSuperview];
+ }
+ completion:^(BOOL finished) {
+ self.incomingCallView = nil;
+ }];
+ }
+
break;
case MXCallStateConnected:
self.isRinging = NO;
@@ -840,6 +905,11 @@ NSString *const kMXKCallViewControllerBackToAppNotification = @"kMXKCallViewCont
}
}
+- (UIView *)createIncomingCallView
+{
+ return nil;
+}
+
#pragma mark - UIResponder Touch Events
- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event

original_message: Add support for incoming calls view


message: Remove incoming call view on destroy method call

diff:
@@ -231,6 +231,8 @@ NSString *const kMXKCallViewControllerBackToAppNotification = @"kMXKCallViewCont
[hideOverlayTimer invalidate];
[updateStatusTimer invalidate];
+ _incomingCallView = nil;
+
[super destroy];
}


message: Add generic annotations for MXKAccountManager

diff:
@@ -45,12 +45,12 @@ extern NSString *const kMXKAccountManagerDidRemoveAccountNotification;
/**
List of all available accounts (enabled and disabled).
*/
-@property (nonatomic, readonly) NSArray* accounts;
+@property (nonatomic, readonly) NSArray<MXKAccount *> *accounts;
/**
List of active accounts (only enabled accounts)
*/
-@property (nonatomic, readonly) NSArray* activeAccounts;
+@property (nonatomic, readonly) NSArray<MXKAccount *> *activeAccounts;
/**
The device token used for Apple Push Notification Service registration.

diff:
@@ -28,7 +28,7 @@ NSString *const kMXKAccountManagerDidRemoveAccountNotification = @"kMXKAccountMa
/**
The list of all accounts (enabled and disabled). Each value is a `MXKAccount` instance.
*/
- NSMutableArray *mxAccounts;
+ NSMutableArray<MXKAccount *> *mxAccounts;
}
@end
@@ -254,12 +254,12 @@ NSString *const kMXKAccountManagerDidRemoveAccountNotification = @"kMXKAccountMa
_storeClass = storeClass;
}
-- (NSArray *)accounts
+- (NSArray<MXKAccount *> *)accounts
{
return [mxAccounts copy];
}
-- (NSArray *)activeAccounts
+- (NSArray<MXKAccount *> *)activeAccounts
{
NSMutableArray *activeAccounts = [NSMutableArray arrayWithCapacity:mxAccounts.count];
for (MXKAccount *account in mxAccounts)
@@ -269,7 +269,7 @@ NSString *const kMXKAccountManagerDidRemoveAccountNotification = @"kMXKAccountMa
[activeAccounts addObject:account];
}
}
- return activeAccounts;
+ return [activeAccounts copy];
}
- (NSData *)apnsDeviceToken


message: Remove copying of activeAccounts

diff:
@@ -269,7 +269,7 @@ NSString *const kMXKAccountManagerDidRemoveAccountNotification = @"kMXKAccountMa
[activeAccounts addObject:account];
}
}
- return [activeAccounts copy];
+ return activeAccounts;
}
- (NSData *)apnsDeviceToken

original_message: Remove copying of activeAccounts


message:
Send audio files and voice messages
vector-im/element-ios/issues/4090 - Added sendAudioFile and sendVoiceMessage methods on the MXKRoomDataSource.

diff:
@@ -504,6 +504,40 @@ extern NSString *const kMXKRoomDataSourceTimelineErrorErrorKey;
success:(void (^)(NSString *eventId))success
failure:(void (^)(NSError *error))failure;
+/**
+ Send an audio file to the room.
+
+ While sending, a fake event will be echoed in the messages list.
+ Once complete, this local echo will be replaced by the event saved by the homeserver.
+
+ @param audioFileLocalURL the local filesystem path of the audio file to send.
+ @param mimeType the mime type of the file.
+ @param success A block object called when the operation succeeds. It returns
+ the event id of the event generated on the homeserver
+ @param failure A block object called when the operation fails.
+ */
+- (void)sendAudioFile:(NSURL *)audioFileLocalURL
+ mimeType:mimeType
+ success:(void (^)(NSString *))success
+ failure:(void (^)(NSError *))failure;
+
+/**
+ Send a voice message to the room.
+
+ While sending, a fake event will be echoed in the messages list.
+ Once complete, this local echo will be replaced by the event saved by the homeserver.
+
+ @param audioFileLocalURL the local filesystem path of the audio file to send.
+ @param mimeType (optional) the mime type of the file. Defaults to `audio/ogg`
+ @param success A block object called when the operation succeeds. It returns
+ the event id of the event generated on the homeserver
+ @param failure A block object called when the operation fails.
+ */
+- (void)sendVoiceMessage:(NSURL *)audioFileLocalURL
+ mimeType:mimeType
+ success:(void (^)(NSString *))success
+ failure:(void (^)(NSError *))failure;
+
/**
Send a file to the room.

diff:
@@ -1861,6 +1861,35 @@ NSString *const kMXKRoomDataSourceTimelineErrorErrorKey = @"kMXKRoomDataSourceTi
}
}
+- (void)sendAudioFile:(NSURL *)audioFileLocalURL mimeType:mimeType success:(void (^)(NSString *))success failure:(void (^)(NSError *))failure
+{
+ __block MXEvent *localEchoEvent = nil;
+
+ [_room sendAudioFile:audioFileLocalURL mimeType:mimeType localEcho:&localEchoEvent success:success failure:failure keepActualFilename:YES];
+
+ if (localEchoEvent)
+ {
+ // Make the data source digest this fake local echo message
+ [self queueEventForProcessing:localEchoEvent withRoomState:self.roomState direction:MXTimelineDirectionForwards];
+ [self processQueuedEvents:nil];
+ }
+}
+
+- (void)sendVoiceMessage:(NSURL *)audioFileLocalURL mimeType:mimeType success:(void (^)(NSString *))success failure:(void (^)(NSError *))failure
+{
+ __block MXEvent *localEchoEvent = nil;
+
+ [_room sendVoiceMessage:audioFileLocalURL mimeType:mimeType localEcho:&localEchoEvent success:success failure:failure keepActualFilename:YES];
+
+ if (localEchoEvent)
+ {
+ // Make the data source digest this fake local echo message
+ [self queueEventForProcessing:localEchoEvent withRoomState:self.roomState direction:MXTimelineDirectionForwards];
+ [self processQueuedEvents:nil];
+ }
+}
+
+
- (void)sendFile:(NSURL *)fileLocalURL mimeType:(NSString*)mimeType success:(void (^)(NSString *))success failure:(void (^)(NSError *))failure
{
__block MXEvent *localEchoEvent = nil;

original_message:
Send audio files and voice messages (#829)

vector-im/element-ios/issues/4090 - Added sendAudioFile and sendVoiceMessage methods on the MXKRoomDataSource.


message: vector-im/element-ios/issues/4090 - Added the VoiceMessage attachement type.

diff:
@@ -29,6 +29,7 @@ typedef enum : NSUInteger {
MXKAttachmentTypeUndefined,
MXKAttachmentTypeImage,
MXKAttachmentTypeAudio,
+ MXKAttachmentTypeVoiceMessage,
MXKAttachmentTypeVideo,
MXKAttachmentTypeLocation,
MXKAttachmentTypeFile,

diff:
@@ -97,8 +97,12 @@ NSString *const kMXKAttachmentErrorDomain = @"kMXKAttachmentErrorDomain";
}
else if ([msgtype isEqualToString:kMXMessageTypeAudio])
{
+ if (eventContent[kMXMessageTypeVoiceMessage]) {
+ _type = MXKAttachmentTypeVoiceMessage;
+ } else {
_type = MXKAttachmentTypeAudio;
}
+ }
else if ([msgtype isEqualToString:kMXMessageTypeVideo])
{
_type = MXKAttachmentTypeVideo;

diff:
if (firstComponent)
{
- CGFloat positionY = (attachment == nil || attachment.type == MXKAttachmentTypeFile || attachment.type == MXKAttachmentTypeAudio) ? MXKROOMBUBBLECELLDATA_TEXTVIEW_DEFAULT_VERTICAL_INSET : 0;
+ CGFloat positionY = (attachment == nil || attachment.type == MXKAttachmentTypeFile || attachment.type == MXKAttachmentTypeAudio || attachment.type == MXKAttachmentTypeVoiceMessage) ? MXKROOMBUBBLECELLDATA_TEXTVIEW_DEFAULT_VERTICAL_INSET : 0;
firstComponent.position = CGPointMake(0, positionY);
}
}

diff:
@@ -1092,7 +1092,7 @@ API_AVAILABLE(ios(10.0)) {
- (BOOL)isBubbleDataContainsFileAttachment
{
return bubbleData.attachment
- && (bubbleData.attachment.type == MXKAttachmentTypeFile || bubbleData.attachment.type == MXKAttachmentTypeAudio)
+ && (bubbleData.attachment.type == MXKAttachmentTypeFile || bubbleData.attachment.type == MXKAttachmentTypeAudio || bubbleData.attachment.type == MXKAttachmentTypeVoiceMessage)
&& bubbleData.attachment.contentURL
&& bubbleData.attachment.contentInfo;
}


message: vector-im/element-ios/issues/4090 - Added voice messages microphone permissions localizable string.

diff:
"local_contacts_access_discovery_warning_title" = "Users discovery";
"local_contacts_access_discovery_warning" = "To discover contacts already using Matrix, %@ can send email addresses and phone numbers in your address book to your chosen Matrix identity server. Where supported, personal data is hashed before sending - please check your identity server's privacy policy for more details.";
+"microphone_access_not_granted_for_voice_message" = "Voice messages require access to the Microphone but %@ doesn't have permission to use it";
+
// Country picker
"country_picker_title" = "Choose a country";


diff:
@@ -97,7 +97,9 @@ NSString *const kMXKAttachmentErrorDomain = @"kMXKAttachmentErrorDomain";
}
else if ([msgtype isEqualToString:kMXMessageTypeAudio])
{
- if (eventContent[kMXMessageTypeVoiceMessage]) {
+ if (eventContent[kMXMessageTypeVoiceMessage] ||
+ eventContent[kMXMessageTypeVoiceMessageMSC2516] ||
+ eventContent[kMXMessageTypeVoiceMessageMSC3245]) {
_type = MXKAttachmentTypeVoiceMessage;
} else {
_type = MXKAttachmentTypeAudio;

original_message: #4094 - Checking for all known voice message types.


message: vector-im/element-ios/issues/4090 - Add custom reply text to voice messages, add duration and samples to sendVoiceMessage.

diff:
"message_reply_to_sender_sent_an_image" = "sent an image.";
"message_reply_to_sender_sent_a_video" = "sent a video.";
"message_reply_to_sender_sent_an_audio_file" = "sent an audio file.";
+"message_reply_to_sender_sent_a_voice_message" = "sent a voice message.";
"message_reply_to_sender_sent_a_file" = "sent a file.";
"message_reply_to_message_to_reply_to_prefix" = "In reply to";

diff:
@@ -95,15 +95,13 @@ NSString *const kMXKAttachmentErrorDomain = @"kMXKAttachmentErrorDomain";
{
_type = MXKAttachmentTypeImage;
}
- else if ([msgtype isEqualToString:kMXMessageTypeAudio])
+ else if (event.isVoiceMessage)
{
- if (eventContent[kMXMessageTypeVoiceMessage] ||
- eventContent[kMXMessageTypeVoiceMessageMSC2516] ||
- eventContent[kMXMessageTypeVoiceMessageMSC3245]) {
_type = MXKAttachmentTypeVoiceMessage;
- } else {
- _type = MXKAttachmentTypeAudio;
}
+ else if ([msgtype isEqualToString:kMXMessageTypeAudio])
+ {
+ _type = MXKAttachmentTypeAudio;
}
else if ([msgtype isEqualToString:kMXMessageTypeVideo])
{

diff:
@@ -546,12 +546,16 @@ extern NSString *const kMXKRoomDataSourceTimelineErrorErrorKey;
@param audioFileLocalURL the local filesystem path of the audio file to send.
@param mimeType (optional) the mime type of the file. Defaults to `audio/ogg`
+ @param duration the length of the voice message in milliseconds
+ @param samples an array of floating point values normalized to [0, 1], boxed within NSNumbers
@param success A block object called when the operation succeeds. It returns
the event id of the event generated on the homeserver
@param failure A block object called when the operation fails.
*/
- (void)sendVoiceMessage:(NSURL *)audioFileLocalURL
mimeType:mimeType
+ duration:(NSTimeInterval)duration
+ samples:(NSArray<NSNumber *> *)samples
success:(void (^)(NSString *))success
failure:(void (^)(NSError *))failure;

diff:
@@ -1885,11 +1885,16 @@ NSString *const kMXKRoomDataSourceTimelineErrorErrorKey = @"kMXKRoomDataSourceTi
}
}
-- (void)sendVoiceMessage:(NSURL *)audioFileLocalURL mimeType:mimeType success:(void (^)(NSString *))success failure:(void (^)(NSError *))failure
+- (void)sendVoiceMessage:(NSURL *)audioFileLocalURL
+ mimeType:mimeType
+ duration:(NSTimeInterval)duration
+ samples:(NSArray<NSNumber *> *)samples
+ success:(void (^)(NSString *))success
+ failure:(void (^)(NSError *))failure
{
__block MXEvent *localEchoEvent = nil;
- [_room sendVoiceMessage:audioFileLocalURL mimeType:mimeType localEcho:&localEchoEvent success:success failure:failure keepActualFilename:YES];
+ [_room sendVoiceMessage:audioFileLocalURL mimeType:mimeType duration:duration samples:samples localEcho:&localEchoEvent success:success failure:failure keepActualFilename:YES];
if (localEchoEvent)
{

diff:
@property (copy, readonly, nonnull) NSString *senderSentAnImage;
@property (copy, readonly, nonnull) NSString *senderSentAVideo;
@property (copy, readonly, nonnull) NSString *senderSentAnAudioFile;
+@property (copy, readonly, nonnull) NSString *senderSentAVoiceMessage;
@property (copy, readonly, nonnull) NSString *senderSentAFile;
@property (copy, readonly, nonnull) NSString *messageToReplyToPrefix;

diff:
_senderSentAnImage = [NSBundle mxk_localizedStringForKey:@"message_reply_to_sender_sent_an_image"];
_senderSentAVideo = [NSBundle mxk_localizedStringForKey:@"message_reply_to_sender_sent_a_video"];
_senderSentAnAudioFile = [NSBundle mxk_localizedStringForKey:@"message_reply_to_sender_sent_an_audio_file"];
+ _senderSentAVoiceMessage = [NSBundle mxk_localizedStringForKey:@"message_reply_to_sender_sent_a_voice_message"];
_senderSentAFile = [NSBundle mxk_localizedStringForKey:@"message_reply_to_sender_sent_a_file"];
_messageToReplyToPrefix = [NSBundle mxk_localizedStringForKey:@"message_reply_to_message_to_reply_to_prefix"];
}


diff:
@@ -44,6 +44,15 @@ NSString *const kMXKRoomDataSourceFailToLoadTimelinePosition = @"kMXKRoomDataSou
NSString *const kMXKRoomDataSourceTimelineError = @"kMXKRoomDataSourceTimelineError";
NSString *const kMXKRoomDataSourceTimelineErrorErrorKey = @"kMXKRoomDataSourceTimelineErrorErrorKey";
+NSString * const MXKRoomDataSourceErrorDomain = @"kMXKRoomDataSourceErrorDomain";
+
+typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
+ MXKRoomDataSourceErrorResendGeneric = 10001,
+ MXKRoomDataSourceErrorResendInvalidMessageType = 10002,
+ MXKRoomDataSourceErrorResendInvalidLocalFilePath = 10003,
+};
+
+
@interface MXKRoomDataSource ()
{
/**
@@ -1959,7 +1968,7 @@ NSString *const kMXKRoomDataSourceTimelineErrorErrorKey = @"kMXKRoomDataSourceTi
return;
}
- MXLogDebug(@"[MXKRoomDataSource] resendEventWithEventId. EventId: %@", event.eventId);
+ MXLogInfo(@"[MXKRoomDataSource] resendEventWithEventId. EventId: %@", event.eventId);
// Check first whether the event is encrypted
if ([event.wireType isEqualToString:kMXEventTypeStringRoomEncrypted])
@@ -2011,7 +2020,8 @@ NSString *const kMXKRoomDataSourceTimelineErrorErrorKey = @"kMXKRoomDataSourceTi
}
else
{
- MXLogDebug(@"[MXKRoomDataSource] resendEventWithEventId: Warning - Unable to resend room message of type: %@", msgType);
+ failure([NSError errorWithDomain:MXKRoomDataSourceErrorDomain code:MXKRoomDataSourceErrorResendGeneric userInfo:nil]);
+ MXLogWarning(@"[MXKRoomDataSource] resendEventWithEventId: Warning - Unable to resend room message of type: %@", msgType);
}
}
else
@@ -2020,6 +2030,40 @@ NSString *const kMXKRoomDataSourceTimelineErrorErrorKey = @"kMXKRoomDataSourceTi
[_room sendMessageWithContent:event.content localEcho:&event success:success failure:failure];
}
}
+ else if ([msgType isEqualToString:kMXMessageTypeAudio])
+ {
+ // Check whether the sending failed while uploading the data.
+ // If the content url corresponds to a upload id, the upload was not complete.
+ NSString *contentURL = event.content[@"url"];
+ if (!contentURL || ![contentURL hasPrefix:kMXMediaUploadIdPrefix])
+ {
+ // Resend the Matrix event by reusing the existing echo
+ [_room sendMessageWithContent:event.content localEcho:&event success:success failure:failure];
+ return;
+ }
+
+ NSString *mimetype = event.content[@"info"][@"mimetype"];
+ NSString *localFilePath = [MXMediaManager cachePathForMatrixContentURI:contentURL andType:mimetype inFolder:_roomId];
+ NSURL *localFileURL = [NSURL URLWithString:localFilePath];
+
+ if (![NSFileManager.defaultManager fileExistsAtPath:localFilePath]) {
+ failure([NSError errorWithDomain:MXKRoomDataSourceErrorDomain code:MXKRoomDataSourceErrorResendInvalidLocalFilePath userInfo:nil]);
+ MXLogWarning(@"[MXKRoomDataSource] resendEventWithEventId: Warning - Unable to resend voice message, invalid file path.");
+ return;
+ }
+
+ // Remove the local echo.
+ [self removeEventWithEventId:eventId];
+
+ if (event.isVoiceMessage) {
+ NSNumber *duration = event.content[kMXMessageContentKeyExtensibleAudio][kMXMessageContentKeyExtensibleAudioDuration];
+ NSArray<NSNumber *> *samples = event.content[kMXMessageContentKeyExtensibleAudio][kMXMessageContentKeyExtensibleAudioWaveform];
+
+ [self sendVoiceMessage:localFileURL mimeType:mimetype duration:duration.doubleValue samples:samples success:success failure:failure];
+ } else {
+ [self sendAudioFile:localFileURL mimeType:mimetype success:success failure:failure];
+ }
+ }
else if ([msgType isEqualToString:kMXMessageTypeVideo])
{
// Check whether the sending failed while uploading the data.
@@ -2029,6 +2073,7 @@ NSString *const kMXKRoomDataSourceTimelineErrorErrorKey = @"kMXKRoomDataSourceTi
{
// TODO: Support resend on attached video when upload has been failed.
MXLogDebug(@"[MXKRoomDataSource] resendEventWithEventId: Warning - Unable to resend attached video (upload was not complete)");
+ failure([NSError errorWithDomain:MXKRoomDataSourceErrorDomain code:MXKRoomDataSourceErrorResendInvalidMessageType userInfo:nil]);
}
else
{
@@ -2062,7 +2107,8 @@ NSString *const kMXKRoomDataSourceTimelineErrorErrorKey = @"kMXKRoomDataSourceTi
}
else
{
- MXLogDebug(@"[MXKRoomDataSource] resendEventWithEventId: Warning - Unable to resend room message of type: %@", msgType);
+ failure([NSError errorWithDomain:MXKRoomDataSourceErrorDomain code:MXKRoomDataSourceErrorResendGeneric userInfo:nil]);
+ MXLogWarning(@"[MXKRoomDataSource] resendEventWithEventId: Warning - Unable to resend room message of type: %@", msgType);
}
}
else
@@ -2073,12 +2119,14 @@ NSString *const kMXKRoomDataSourceTimelineErrorErrorKey = @"kMXKRoomDataSourceTi
}
else
{
- MXLogDebug(@"[MXKRoomDataSource] resendEventWithEventId: Warning - Unable to resend room message of type: %@", msgType);
+ failure([NSError errorWithDomain:MXKRoomDataSourceErrorDomain code:MXKRoomDataSourceErrorResendInvalidMessageType userInfo:nil]);
+ MXLogWarning(@"[MXKRoomDataSource] resendEventWithEventId: Warning - Unable to resend room message of type: %@", msgType);
}
}
else
{
- MXLogDebug(@"[MXKRoomDataSource] MXKRoomDataSource: Warning - Only resend of MXEventTypeRoomMessage is allowed. Event.type: %@", event.type);
+ failure([NSError errorWithDomain:MXKRoomDataSourceErrorDomain code:MXKRoomDataSourceErrorResendInvalidMessageType userInfo:nil]);
+ MXLogWarning(@"[MXKRoomDataSource] MXKRoomDataSource: Warning - Only resend of MXEventTypeRoomMessage is allowed. Event.type: %@", event.type);
}
}

original_message: #4094 - Implemented retrying for failed audio file and voice messages, always calling completion blocks.


message: vector-im/element-ios/issues/4090 - Switched the sendVoiceMessage method duration parameter to an integer.

diff:
@@ -554,7 +554,7 @@ extern NSString *const kMXKRoomDataSourceTimelineErrorErrorKey;
*/
- (void)sendVoiceMessage:(NSURL *)audioFileLocalURL
mimeType:mimeType
- duration:(NSTimeInterval)duration
+ duration:(NSUInteger)duration
samples:(NSArray<NSNumber *> *)samples
success:(void (^)(NSString *))success
failure:(void (^)(NSError *))failure;

diff:
@@ -1896,7 +1896,7 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
- (void)sendVoiceMessage:(NSURL *)audioFileLocalURL
mimeType:mimeType
- duration:(NSTimeInterval)duration
+ duration:(NSUInteger)duration
samples:(NSArray<NSNumber *> *)samples
success:(void (^)(NSString *))success
failure:(void (^)(NSError *))failure


message: vector-im/element-ios/issues/4577 - Decrypt attachments on a background thread.

diff:
@@ -290,17 +290,18 @@ NSString *const kMXKAttachmentErrorDomain = @"kMXKAttachmentErrorDomain";
MXStrongifyAndReturnIfNil(self);
NSInputStream *instream = [[NSInputStream alloc] initWithFileAtPath:self.thumbnailCachePath];
NSOutputStream *outstream = [[NSOutputStream alloc] initToMemory];
- NSError *err = [MXEncryptedAttachments decryptAttachment:self->thumbnailFile inputStream:instream outputStream:outstream];
+ [MXEncryptedAttachments decryptAttachment:self->thumbnailFile inputStream:instream outputStream:outstream success:^{
+ UIImage *img = [UIImage imageWithData:[outstream propertyForKey:NSStreamDataWrittenToMemoryStreamKey]];
+ // Save this image to in-memory cache.
+ [MXMediaManager cacheImage:img withCachePath:self.thumbnailCachePath];
+ onSuccess(self, img);
+ } failure:^(NSError *err) {
if (err) {
MXLogDebug(@"Error decrypting attachment! %@", err.userInfo);
if (onFailure) onFailure(self, err);
return;
}
-
- UIImage *img = [UIImage imageWithData:[outstream propertyForKey:NSStreamDataWrittenToMemoryStreamKey]];
- // Save this image to in-memory cache.
- [MXMediaManager cacheImage:img withCachePath:self.thumbnailCachePath];
- onSuccess(self, img);
+ }];
};
if ([[NSFileManager defaultManager] fileExistsAtPath:_thumbnailCachePath])
@@ -398,13 +399,15 @@ NSString *const kMXKAttachmentErrorDomain = @"kMXKAttachmentErrorDomain";
// decrypt the encrypted file
NSInputStream *instream = [[NSInputStream alloc] initWithFileAtPath:self.cacheFilePath];
NSOutputStream *outstream = [[NSOutputStream alloc] initToMemory];
- NSError *err = [MXEncryptedAttachments decryptAttachment:self->contentFile inputStream:instream outputStream:outstream];
+ [MXEncryptedAttachments decryptAttachment:self->contentFile inputStream:instream outputStream:outstream success:^{
+ onSuccess([outstream propertyForKey:NSStreamDataWrittenToMemoryStreamKey]);
+ } failure:^(NSError *err) {
if (err)
{
MXLogDebug(@"Error decrypting attachment! %@", err.userInfo);
return;
}
- onSuccess([outstream propertyForKey:NSStreamDataWrittenToMemoryStreamKey]);
+ }];
}
else
{
@@ -428,12 +431,14 @@ NSString *const kMXKAttachmentErrorDomain = @"kMXKAttachmentErrorDomain";
NSInputStream *inStream = [NSInputStream inputStreamWithFileAtPath:self.cacheFilePath];
NSOutputStream *outStream = [NSOutputStream outputStreamToFileAtPath:tempPath append:NO];
- NSError *err = [MXEncryptedAttachments decryptAttachment:self->contentFile inputStream:inStream outputStream:outStream];
+ [MXEncryptedAttachments decryptAttachment:self->contentFile inputStream:inStream outputStream:outStream success:^{
+ onSuccess(tempPath);
+ } failure:^(NSError *err) {
if (err) {
if (onFailure) onFailure(err);
return;
}
- onSuccess(tempPath);
+ }];
} failure:onFailure];
}


message: vector-im/element-ios/issues/4578 - Added generic `others` storage dictionary on MXKAccount.

diff:
@@ -148,6 +148,11 @@ typedef BOOL (^MXKAccountOnCertificateChange)(MXKAccount *mxAccount, NSData *cer
*/
@property (nonatomic, readonly) BOOL pushNotificationServiceIsActive;
+/**
+ Transient information storage.
+ */
+@property (nonatomic, strong, readonly) NSMutableDictionary<NSString *, id<NSCoding>> *others;
+
/**
Enable Push notification based on Apple Push Notification Service (APNS).

diff:
@@ -76,7 +76,7 @@ static NSArray<NSNumber*> *initialSyncSilentErrorsHTTPStatusCodes;
// Background sync management
MXOnBackgroundSyncDone backgroundSyncDone;
- MXOnBackgroundSyncFail backgroundSyncfails;
+ MXOnBackgroundSyncFail backgroundSyncFails;
NSTimer* backgroundSyncTimer;
// Observe UIApplicationSignificantTimeChangeNotification to refresh MXRoomSummaries on time formatting change.
@@ -89,6 +89,8 @@ static NSArray<NSNumber*> *initialSyncSilentErrorsHTTPStatusCodes;
@property (nonatomic, strong) id<MXBackgroundTask> backgroundTask;
@property (nonatomic, strong) id<MXBackgroundTask> backgroundSyncBgTask;
+@property (nonatomic, strong) NSMutableDictionary<NSString *, id<NSCoding>> *others;
+
@end
@implementation MXKAccount
@@ -225,6 +227,8 @@ static NSArray<NSNumber*> *initialSyncSilentErrorsHTTPStatusCodes;
_showDecryptedContentInNotifications = [coder decodeBoolForKey:@"showDecryptedContentInNotifications"];
+ _others = [coder decodeObjectForKey:@"others"];
+
// Refresh device information
[self loadDeviceInformation:nil failure:nil];
}
@@ -284,6 +288,8 @@ static NSArray<NSNumber*> *initialSyncSilentErrorsHTTPStatusCodes;
[coder encodeBool:_warnedAboutEncryption forKey:@"warnedAboutEncryption"];
[coder encodeBool:_showDecryptedContentInNotifications forKey:@"showDecryptedContentInNotifications"];
+
+ [coder encodeObject:_others forKey:@"others"];
}
#pragma mark - Properties
@@ -614,6 +620,15 @@ static NSArray<NSNumber*> *initialSyncSilentErrorsHTTPStatusCodes;
[[MXKAccountManager sharedManager] saveAccounts];
}
+- (NSMutableDictionary<NSString *, id<NSCoding>> *)others
+{
+ if(_others == nil) {
+ _others = [NSMutableDictionary dictionary];
+ }
+
+ return _others;
+}
+
#pragma mark - Matrix user's profile
- (void)setUserDisplayName:(NSString*)displayname success:(void (^)(void))success failure:(void (^)(NSError *error))failure
@@ -1835,9 +1850,9 @@ static NSArray<NSNumber*> *initialSyncSilentErrorsHTTPStatusCodes;
backgroundSyncTimer = nil;
}
- if (backgroundSyncfails && error)
+ if (backgroundSyncFails && error)
{
- backgroundSyncfails(error);
+ backgroundSyncFails(error);
}
if (backgroundSyncDone && !error)
@@ -1846,7 +1861,7 @@ static NSArray<NSNumber*> *initialSyncSilentErrorsHTTPStatusCodes;
}
backgroundSyncDone = nil;
- backgroundSyncfails = nil;
+ backgroundSyncFails = nil;
// End background task
if (self.backgroundSyncBgTask.isRunning)
@@ -1874,7 +1889,7 @@ static NSArray<NSNumber*> *initialSyncSilentErrorsHTTPStatusCodes;
MXLogDebug(@"[MXKAccount] starts a background Sync");
backgroundSyncDone = success;
- backgroundSyncfails = failure;
+ backgroundSyncFails = failure;
MXWeakify(self);


message: vector-im/element-ios/issues/4577 - Fixed tests.

diff:
NSInputStream *inputStream = [NSInputStream inputStreamWithData:ctData];
NSOutputStream *outputStream = [NSOutputStream outputStreamToMemory];
- NSError *err = [MXEncryptedAttachments decryptAttachment:inputInfo inputStream:inputStream outputStream:outputStream];
- XCTAssertNil(err);
+ [MXEncryptedAttachments decryptAttachment:inputInfo inputStream:inputStream outputStream:outputStream success:^{
NSData *gotData = [outputStream propertyForKey:NSStreamDataWrittenToMemoryStreamKey];
NSData *wantData = [[NSData alloc] initWithBase64EncodedString:[MXBase64Tools padBase64:want] options:0];
XCTAssertEqualObjects(wantData, gotData, "Decrypted data did not match expectation.");
+ } failure:^(NSError *error) {
+ XCTFail();
+ }];
}
}


diff:
@@ -622,7 +622,8 @@ static NSArray<NSNumber*> *initialSyncSilentErrorsHTTPStatusCodes;
- (NSMutableDictionary<NSString *, id<NSCoding>> *)others
{
- if(_others == nil) {
+ if(_others == nil)
+ {
_others = [NSMutableDictionary dictionary];
}

original_message:
Update MatrixKit/Models/Account/MXKAccount.m

Co-authored-by: manuroe <manuroe@users.noreply.github.com>


diff:
@@ -153,6 +153,10 @@ typedef enum : NSUInteger {
*/
- (void)decryptToTempFile:(void (^_Nullable)(NSString *_Nullable))onSuccess failure:(void (^_Nullable)(NSError * _Nullable error))onFailure;
+
+/** Deletes all previously created temporary files */
++ (void)clearCache;
+
/**
Gets the thumbnails for this attachment, downloading it or loading it from disk cache
if necessary

diff:
@@ -32,6 +32,7 @@ static const int kThumbnailWidth = 320;
static const int kThumbnailHeight = 240;
NSString *const kMXKAttachmentErrorDomain = @"kMXKAttachmentErrorDomain";
+NSString *const kMXKAttachmentFileNameBase = @"attatchment";
@interface MXKAttachment ()
{
@@ -447,7 +448,7 @@ NSString *const kMXKAttachmentErrorDomain = @"kMXKAttachmentErrorDomain";
// create a file with an appropriate extension because iOS detects based on file extension
// all over the place
NSString *ext = [MXTools fileExtensionFromContentType:mimetype];
- NSString *filenameTemplate = [NSString stringWithFormat:@"attatchment.XXXXXX%@", ext];
+ NSString *filenameTemplate = [NSString stringWithFormat:@"%@.XXXXXX%@", kMXKAttachmentFileNameBase, ext];
NSString *template = [NSTemporaryDirectory() stringByAppendingPathComponent:filenameTemplate];
const char *templateCstr = [template fileSystemRepresentation];
@@ -467,6 +468,25 @@ NSString *const kMXKAttachmentErrorDomain = @"kMXKAttachmentErrorDomain";
return tempPath;
}
++ (void)clearCache
+{
+ NSString *temporaryDirectoryPath = NSTemporaryDirectory();
+ NSDirectoryEnumerator<NSString *> *enumerator = [NSFileManager.defaultManager enumeratorAtPath:temporaryDirectoryPath];
+
+ NSString *filePath;
+ while (filePath = [enumerator nextObject]) {
+ if(![filePath containsString:kMXKAttachmentFileNameBase]) {
+ continue;
+ }
+
+ NSError *error;
+ BOOL result = [NSFileManager.defaultManager removeItemAtPath:[temporaryDirectoryPath stringByAppendingPathComponent:filePath] error:&error];
+ if (!result && error) {
+ MXLogError(@"[MXKAttachment] Failed deleting temporary file with error: %@", error);
+ }
+ }
+}
+
- (void)prepare:(void (^)(void))onAttachmentReady failure:(void (^)(NSError *error))onFailure
{
if ([[NSFileManager defaultManager] fileExistsAtPath:_cacheFilePath])

diff:
+MXKAttachment: Added method for deleting all previously created temporary, decrypted attachments.
\ No newline at end of file


message: Fixes vector-im/element-ios/issues/4830 - Automatically dismissing invites for empty rooms after failing to join.

diff:
// Room
"room_please_select" = "Please select a room";
"room_error_join_failed_title" = "Failed to join room";
-"room_error_join_failed_empty_room" = "It is not currently possible to re-join an empty room.";
+"room_error_join_failed_empty_room" = "It is not currently possible to join an empty room.";
"room_error_name_edition_not_authorized" = "You are not authorized to edit this room name";
"room_error_topic_edition_not_authorized" = "You are not authorized to edit this room topic";
"room_error_cannot_load_timeline" = "Failed to load timeline";

diff:
#import "MXKAttachmentsViewController.h"
#import "MXKAttachmentAnimator.h"
+typedef NS_ENUM(NSUInteger, MXKRoomViewControllerJoinRoomResult) {
+ MXKRoomViewControllerJoinRoomResultSuccess,
+ MXKRoomViewControllerJoinRoomResultFailureRoomEmpty,
+ MXKRoomViewControllerJoinRoomResultFailureJoinInProgress,
+ MXKRoomViewControllerJoinRoomResultFailureGeneric
+};
+
/**
This view controller displays messages of a room. Only one matrix session is handled by this view controller.
*/
@param completion the block to execute at the end of the operation.
You may specify nil for this parameter.
*/
-- (void)joinRoom:(void(^)(BOOL succeed))completion;
+- (void)joinRoom:(void(^)(MXKRoomViewControllerJoinRoomResult result))completion;
/**
Join a room with a room id or an alias.
@param completion the block to execute at the end of the operation.
You may specify nil for this parameter.
*/
-- (void)joinRoomWithRoomIdOrAlias:(NSString*)roomIdOrAlias viaServers:(NSArray<NSString*>*)viaServers andSignUrl:(NSString*)signUrl completion:(void(^)(BOOL succeed))completion;
+- (void)joinRoomWithRoomIdOrAlias:(NSString*)roomIdOrAlias
+ viaServers:(NSArray<NSString*>*)viaServers
+ andSignUrl:(NSString*)signUrl
+ completion:(void(^)(MXKRoomViewControllerJoinRoomResult result))completion;
/**
Update view controller appearance when the user is about to leave the displayed room.

diff:
}
}
-- (void)joinRoom:(void(^)(BOOL succeed))completion
+- (void)joinRoom:(void(^)(MXKRoomViewControllerJoinRoomResult result))completion
{
- // Check whether a join request is not already running
- if (!joinRoomRequest)
+ if (joinRoomRequest != nil)
{
+ if (completion)
+ {
+ completion(MXKRoomViewControllerJoinRoomResultFailureJoinInProgress);
+ }
+ return;
+ }
+
[self startActivityIndicator];
joinRoomRequest = [roomDataSource.room join:^{
if (completion)
{
- completion(YES);
+ completion(MXKRoomViewControllerJoinRoomResultSuccess);
}
} failure:^(NSError *error) {
-
MXLogDebug(@"[MXKRoomVC] Failed to join room (%@)", self->roomDataSource.room.summary.displayname);
-
- self->joinRoomRequest = nil;
- [self stopActivityIndicator];
-
- // Show the error to the end user
- MXWeakify(self);
- NSString *msg = [error.userInfo valueForKey:NSLocalizedDescriptionKey];
- if ([msg isEqualToString:@"No known servers"])
- {
- // minging kludge until https://matrix.org/jira/browse/SYN-678 is fixed
- // 'Error when trying to join an empty room should be more explicit'
- msg = [NSBundle mxk_localizedStringForKey:@"room_error_join_failed_empty_room"];
+ [self processRoomJoinFailureWithError:error completion:completion];
+ }];
}
- [self->currentAlert dismissViewControllerAnimated:NO completion:nil];
-
- self->currentAlert = [UIAlertController alertControllerWithTitle:[NSBundle mxk_localizedStringForKey:@"room_error_join_failed_title"] message:msg preferredStyle:UIAlertControllerStyleAlert];
-
- [self->currentAlert addAction:[UIAlertAction actionWithTitle:[NSBundle mxk_localizedStringForKey:@"ok"]
- style:UIAlertActionStyleDefault
- handler:^(UIAlertAction * action) {
-
- MXStrongifyAndReturnIfNil(self);
- self->currentAlert = nil;
-
- }]];
-
- [self presentViewController:self->currentAlert animated:YES completion:nil];
-
+- (void)joinRoomWithRoomIdOrAlias:(NSString*)roomIdOrAlias
+ viaServers:(NSArray<NSString*>*)viaServers
+ andSignUrl:(NSString*)signUrl
+ completion:(void(^)(MXKRoomViewControllerJoinRoomResult result))completion
+{
+ if (joinRoomRequest != nil)
+ {
if (completion)
{
- completion(NO);
+ completion(MXKRoomViewControllerJoinRoomResultFailureJoinInProgress);
}
- }];
- }
- else if (completion)
- {
- completion (NO);
- }
+ return;
}
-- (void)joinRoomWithRoomIdOrAlias:(NSString*)roomIdOrAlias viaServers:(NSArray<NSString*>*)viaServers andSignUrl:(NSString*)signUrl completion:(void(^)(BOOL succeed))completion
-{
- // Check whether a join request is not already running
- if (!joinRoomRequest)
- {
[self startActivityIndicator];
void (^success)(MXRoom *room) = ^(MXRoom *room) {
if (completion)
{
- completion(YES);
+ completion(MXKRoomViewControllerJoinRoomResultSuccess);
}
}];
};
void (^failure)(NSError *error) = ^(NSError *error) {
-
MXLogDebug(@"[MXKRoomVC] Failed to join room (%@)", roomIdOrAlias);
+ [self processRoomJoinFailureWithError:error completion:completion];
+ };
+
+ // Does the join need to be validated before?
+ if (signUrl)
+ {
+ joinRoomRequest = [self.mainSession joinRoom:roomIdOrAlias viaServers:viaServers withSignUrl:signUrl success:success failure:failure];
+ }
+ else
+ {
+ joinRoomRequest = [self.mainSession joinRoom:roomIdOrAlias viaServers:viaServers success:success failure:failure];
+ }
+}
+- (void)processRoomJoinFailureWithError:(NSError *)error completion:(void(^)(MXKRoomViewControllerJoinRoomResult result))completion
+{
self->joinRoomRequest = nil;
[self stopActivityIndicator];
// Show the error to the end user
NSString *msg = [error.userInfo valueForKey:NSLocalizedDescriptionKey];
- if ([msg isEqualToString:@"No known servers"])
+
+ // FIXME: We should hide this inside the SDK and expose it as a domain specific error
+ BOOL isRoomEmpty = [msg isEqualToString:@"No known servers"];
+ if (isRoomEmpty)
{
// minging kludge until https://matrix.org/jira/browse/SYN-678 is fixed
// 'Error when trying to join an empty room should be more explicit'
msg = [NSBundle mxk_localizedStringForKey:@"room_error_join_failed_empty_room"];
}
+
MXWeakify(self);
[self->currentAlert dismissViewControllerAnimated:NO completion:nil];
MXStrongifyAndReturnIfNil(self);
self->currentAlert = nil;
- }]];
-
- [self presentViewController:self->currentAlert animated:YES completion:nil];
-
if (completion)
{
- completion(NO);
+ completion((isRoomEmpty ? MXKRoomViewControllerJoinRoomResultFailureRoomEmpty : MXKRoomViewControllerJoinRoomResultFailureGeneric));
}
- };
+ }]];
- // Does the join need to be validated before?
- if (signUrl)
- {
- joinRoomRequest = [self.mainSession joinRoom:roomIdOrAlias viaServers:viaServers withSignUrl:signUrl success:success failure:failure];
- }
- else
- {
- joinRoomRequest = [self.mainSession joinRoom:roomIdOrAlias viaServers:viaServers success:success failure:failure];
- }
- }
- else if (completion)
- {
- completion (NO);
- }
+ [self presentViewController:self->currentAlert animated:YES completion:nil];
}
- (void)leaveRoomOnEvent:(MXEvent*)event

diff:
+Exposed more room joining result types in the completion handler.
\ No newline at end of file


message: vector-im/element-ios/issues/4717 - Exposed new room name localizable string to use for empty direct messages.

diff:
"room_displayname_empty_room" = "Empty room";
"room_displayname_two_members" = "%@ and %@";
"room_displayname_more_than_two_members" = "%@ and %@ others";
+"room_displayname_all_other_participants_left" = "%@ (Left)";
// Settings
"settings" = "Settings";

diff:
*/
@interface MXKRoomNameStringLocalizations : NSObject <MXRoomNameStringsLocalizable>
-@property (copy, readonly, nonnull) NSString *emptyRoom;
-@property (copy, readonly, nonnull) NSString *twoMembers;
-@property (copy, readonly, nonnull) NSString *moreThanTwoMembers;
-
@end

diff:
#import "NSBundle+MatrixKit.h"
+@interface MXKRoomNameStringLocalizations ()
+
+@property (nonatomic, copy) NSString *emptyRoom;
+@property (nonatomic, copy) NSString *twoMembers;
+@property (nonatomic, copy) NSString *moreThanTwoMembers;
+@property (nonatomic, copy) NSString *allOtherParticipantsLeft;
+
+@end
+
@implementation MXKRoomNameStringLocalizations
- (instancetype)init
_emptyRoom = [NSBundle mxk_localizedStringForKey:@"room_displayname_empty_room"];
_twoMembers = [NSBundle mxk_localizedStringForKey:@"room_displayname_two_members"];
_moreThanTwoMembers = [NSBundle mxk_localizedStringForKey:@"room_displayname_more_than_two_members"];
+ _allOtherParticipantsLeft = [NSBundle mxk_localizedStringForKey:@"room_displayname_all_other_participants_left"];
}
return self;
}

diff:
+Exposed new room name localizable string to use for empty direct messages.
\ No newline at end of file


message: vector-im/element-ios/issues/4899 - Added dynamism and compile time safety to room name and send reply event localizable strings.

diff:
328E410424CB135100DC4490 /* MatrixKitVersion.m in Sources */ = {isa = PBXBuildFile; fileRef = 328E410224CB135100DC4490 /* MatrixKitVersion.m */; };
329CF77B1AA9FDE000A4753F /* MXKRoomIOSBubbleTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 329CF77A1AA9FDE000A4753F /* MXKRoomIOSBubbleTableViewCell.m */; };
32B046722101EB5E002A24A1 /* MXRoom+Sync.m in Sources */ = {isa = PBXBuildFile; fileRef = 32B046712101EB5E002A24A1 /* MXRoom+Sync.m */; };
- 32BA86B721538B35008F277E /* MXKRoomNameStringLocalizations.m in Sources */ = {isa = PBXBuildFile; fileRef = 32BA86B621538B35008F277E /* MXKRoomNameStringLocalizations.m */; };
+ 32BA86B721538B35008F277E /* MXKRoomNameStringLocalizer.m in Sources */ = {isa = PBXBuildFile; fileRef = 32BA86B621538B35008F277E /* MXKRoomNameStringLocalizer.m */; };
32BA86BA21538FFC008F277E /* MXKEventFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 32BA86B821538FFC008F277E /* MXKEventFormatter.m */; };
32C3ABBA22C4F23B00CA0449 /* MXAggregatedReactions+MatrixKit.m in Sources */ = {isa = PBXBuildFile; fileRef = 32C3ABB922C4F23B00CA0449 /* MXAggregatedReactions+MatrixKit.m */; };
32CEE2231AB1E37600F7C74D /* MXKRecentListViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 32CEE2211AB1E37600F7C74D /* MXKRecentListViewController.m */; };
B12C471020BED312004FBF96 /* MXKErrorPresentableBuilder.m in Sources */ = {isa = PBXBuildFile; fileRef = B12C470F20BED312004FBF96 /* MXKErrorPresentableBuilder.m */; };
B12C56F22396D75500FAC6DE /* UITextView+MatrixKit.m in Sources */ = {isa = PBXBuildFile; fileRef = B12C56F12396D75500FAC6DE /* UITextView+MatrixKit.m */; };
B13652F8221E9E7A00313B09 /* MXKMessageTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = B13652F7221E9E7A00313B09 /* MXKMessageTextView.m */; };
- B164380C210603CD00DBB3FD /* MXKSendReplyEventStringLocalizations.m in Sources */ = {isa = PBXBuildFile; fileRef = B164380B210603CD00DBB3FD /* MXKSendReplyEventStringLocalizations.m */; };
+ B164380C210603CD00DBB3FD /* MXKSendReplyEventStringLocalizer.m in Sources */ = {isa = PBXBuildFile; fileRef = B164380B210603CD00DBB3FD /* MXKSendReplyEventStringLocalizer.m */; };
B1668AC021072F93002B14F1 /* MXKSlashCommands.m in Sources */ = {isa = PBXBuildFile; fileRef = B1668ABF21072F93002B14F1 /* MXKSlashCommands.m */; };
CE14CA661E80122600E329A3 /* MXKAttachmentAnimator.m in Sources */ = {isa = PBXBuildFile; fileRef = CE14CA631E80122600E329A3 /* MXKAttachmentAnimator.m */; };
CE14CA671E80122600E329A3 /* MXKAttachmentInteractionController.m in Sources */ = {isa = PBXBuildFile; fileRef = CE14CA651E80122600E329A3 /* MXKAttachmentInteractionController.m */; };
329CF77A1AA9FDE000A4753F /* MXKRoomIOSBubbleTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MXKRoomIOSBubbleTableViewCell.m; sourceTree = "<group>"; };
32B046702101EB5E002A24A1 /* MXRoom+Sync.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "MXRoom+Sync.h"; sourceTree = "<group>"; };
32B046712101EB5E002A24A1 /* MXRoom+Sync.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "MXRoom+Sync.m"; sourceTree = "<group>"; };
- 32BA86B521538B35008F277E /* MXKRoomNameStringLocalizations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MXKRoomNameStringLocalizations.h; sourceTree = "<group>"; };
- 32BA86B621538B35008F277E /* MXKRoomNameStringLocalizations.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MXKRoomNameStringLocalizations.m; sourceTree = "<group>"; };
+ 32BA86B521538B35008F277E /* MXKRoomNameStringLocalizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MXKRoomNameStringLocalizer.h; sourceTree = "<group>"; };
+ 32BA86B621538B35008F277E /* MXKRoomNameStringLocalizer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MXKRoomNameStringLocalizer.m; sourceTree = "<group>"; };
32BA86B821538FFC008F277E /* MXKEventFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MXKEventFormatter.m; sourceTree = "<group>"; };
32BA86B921538FFC008F277E /* MXKEventFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MXKEventFormatter.h; sourceTree = "<group>"; };
32BDC981211AD6D10064AF51 /* AUTHORS.rst */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = AUTHORS.rst; sourceTree = "<group>"; };
B13652F6221E9E7A00313B09 /* MXKMessageTextView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MXKMessageTextView.h; sourceTree = "<group>"; };
B13652F7221E9E7A00313B09 /* MXKMessageTextView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MXKMessageTextView.m; sourceTree = "<group>"; };
B13AC545246447ED00A6B899 /* MatrixKit.podspec */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; path = MatrixKit.podspec; sourceTree = "<group>"; };
- B164380A210603CD00DBB3FD /* MXKSendReplyEventStringLocalizations.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MXKSendReplyEventStringLocalizations.h; sourceTree = "<group>"; };
- B164380B210603CD00DBB3FD /* MXKSendReplyEventStringLocalizations.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MXKSendReplyEventStringLocalizations.m; sourceTree = "<group>"; };
+ B164380A210603CD00DBB3FD /* MXKSendReplyEventStringLocalizer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MXKSendReplyEventStringLocalizer.h; sourceTree = "<group>"; };
+ B164380B210603CD00DBB3FD /* MXKSendReplyEventStringLocalizer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MXKSendReplyEventStringLocalizer.m; sourceTree = "<group>"; };
B1668ABE21072F93002B14F1 /* MXKSlashCommands.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MXKSlashCommands.h; sourceTree = "<group>"; };
B1668ABF21072F93002B14F1 /* MXKSlashCommands.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MXKSlashCommands.m; sourceTree = "<group>"; };
B455B95A7B9ECAD75BA21E12 /* Pods_MatrixKitSamplePods_MatrixKitTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_MatrixKitSamplePods_MatrixKitTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
32BA86B921538FFC008F277E /* MXKEventFormatter.h */,
32BA86B821538FFC008F277E /* MXKEventFormatter.m */,
EC6DC7BA24F9562600B6C40F /* MarkdownToHTMLRenderer.swift */,
- 32BA86B521538B35008F277E /* MXKRoomNameStringLocalizations.h */,
- 32BA86B621538B35008F277E /* MXKRoomNameStringLocalizations.m */,
+ 32BA86B521538B35008F277E /* MXKRoomNameStringLocalizer.h */,
+ 32BA86B621538B35008F277E /* MXKRoomNameStringLocalizer.m */,
);
path = EventFormatter;
sourceTree = "<group>";
F07E180C1ABC2EDA00DE3766 /* MXKRoomDataSource.m */,
3230A3731ACADC1800CC57F5 /* MXKRoomDataSourceManager.h */,
3230A3741ACADC1800CC57F5 /* MXKRoomDataSourceManager.m */,
- B164380A210603CD00DBB3FD /* MXKSendReplyEventStringLocalizations.h */,
- B164380B210603CD00DBB3FD /* MXKSendReplyEventStringLocalizations.m */,
+ B164380A210603CD00DBB3FD /* MXKSendReplyEventStringLocalizer.h */,
+ B164380B210603CD00DBB3FD /* MXKSendReplyEventStringLocalizer.m */,
B1668ABE21072F93002B14F1 /* MXKSlashCommands.h */,
B1668ABF21072F93002B14F1 /* MXKSlashCommands.m */,
91FE762A27047EB700E035D9 /* MXKURLPreviewDataProtocol.h */,
328E410324CB135100DC4490 /* MatrixKitVersion.m in Sources */,
F095E5101B25899F009606CE /* MXKEmail.m in Sources */,
321313C91AEFC2D500A9B035 /* MXKRoomIOSOutgoingBubbleTableViewCell.m in Sources */,
- B164380C210603CD00DBB3FD /* MXKSendReplyEventStringLocalizations.m in Sources */,
+ B164380C210603CD00DBB3FD /* MXKSendReplyEventStringLocalizer.m in Sources */,
F0FDF2671E53586A00D23C47 /* MXKCountryPickerViewController.m in Sources */,
B12C471020BED312004FBF96 /* MXKErrorPresentableBuilder.m in Sources */,
F00FA85C1C0867F900E25826 /* MXKRoomIncomingAttachmentBubbleCell.m in Sources */,
F095E50F1B25899F009606CE /* MXKContactManager.m in Sources */,
F09617C31DE881D800093E9D /* MXKEncryptionInfoView.m in Sources */,
F0CE56EB1AA8BB5E003BE77A /* MXKSampleMainTableViewController.m in Sources */,
- 32BA86B721538B35008F277E /* MXKRoomNameStringLocalizations.m in Sources */,
+ 32BA86B721538B35008F277E /* MXKRoomNameStringLocalizer.m in Sources */,
F0AD3CC71B289441002E0899 /* MXKInterleavedRecentTableViewCell.m in Sources */,
F0DB1AC51B025D9400A3FA54 /* MXKSampleRoomMemberTableViewCell.m in Sources */,
F08D35211FD0134900A0C2FB /* MXKPieChartHUD.m in Sources */,

diff:
"room_displayname_empty_room" = "Empty room";
"room_displayname_two_members" = "%@ and %@";
"room_displayname_more_than_two_members" = "%@ and %@ others";
-"room_displayname_all_other_participants_left" = "%@ (Left)";
+"room_displayname_all_other_members_left" = "%@ (Left)";
// Settings
"settings" = "Settings";

diff:
@@ -1395,6 +1395,10 @@ public class MatrixKitL10n: NSObject {
public static var roomDetailsTitle: String {
return MatrixKitL10n.tr("room_details_title")
}
+ /// %@ (Left)
+ public static func roomDisplaynameAllOtherMembersLeft(_ p1: String) -> String {
+ return MatrixKitL10n.tr("room_displayname_all_other_members_left", p1)
+ }
/// Empty room
public static var roomDisplaynameEmptyRoom: String {
return MatrixKitL10n.tr("room_displayname_empty_room")

diff:
#import "MXKAppSettings.h"
-#import "MXKSendReplyEventStringLocalizations.h"
+#import "MXKSendReplyEventStringLocalizer.h"
#import "MXKSlashCommands.h"
@@ -1736,9 +1736,9 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
NSString *sanitizedText = [self sanitizedMessageText:text];
NSString *html = [self htmlMessageFromSanitizedText:sanitizedText];
- id<MXSendReplyEventStringsLocalizable> stringLocalizations = [MXKSendReplyEventStringLocalizations new];
+ id<MXSendReplyEventStringLocalizer> stringLocalizer = [MXKSendReplyEventStringLocalizer new];
- [_room sendReplyToEvent:eventToReply withTextMessage:sanitizedText formattedTextMessage:html stringLocalizations:stringLocalizations localEcho:&localEchoEvent success:success failure:failure];
+ [_room sendReplyToEvent:eventToReply withTextMessage:sanitizedText formattedTextMessage:html stringLocalizer:stringLocalizer localEcho:&localEchoEvent success:success failure:failure];
if (localEchoEvent)
{

change_type: DELETE

diff:
-/*
- Copyright 2018 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/Foundation.h>
-#import <MatrixSDK/MXSendReplyEventStringsLocalizable.h>
-
-/**
- A `MXKSendReplyEventStringLocalizations` instance represents string localizations used when send reply event to a message in a room.
- */
-@interface MXKSendReplyEventStringLocalizations : NSObject<MXSendReplyEventStringsLocalizable>
-
-@property (copy, readonly, nonnull) NSString *senderSentAnImage;
-@property (copy, readonly, nonnull) NSString *senderSentAVideo;
-@property (copy, readonly, nonnull) NSString *senderSentAnAudioFile;
-@property (copy, readonly, nonnull) NSString *senderSentAVoiceMessage;
-@property (copy, readonly, nonnull) NSString *senderSentAFile;
-@property (copy, readonly, nonnull) NSString *messageToReplyToPrefix;
-
-@end

diff:
-/*
- Copyright 2018 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 "MXKSendReplyEventStringLocalizations.h"
-
-#import "NSBundle+MatrixKit.h"
-
-@implementation MXKSendReplyEventStringLocalizations
-
-- (instancetype)init
-{
- self = [super init];
- if (self) {
- _senderSentAnImage = [NSBundle mxk_localizedStringForKey:@"message_reply_to_sender_sent_an_image"];
- _senderSentAVideo = [NSBundle mxk_localizedStringForKey:@"message_reply_to_sender_sent_a_video"];
- _senderSentAnAudioFile = [NSBundle mxk_localizedStringForKey:@"message_reply_to_sender_sent_an_audio_file"];
- _senderSentAVoiceMessage = [NSBundle mxk_localizedStringForKey:@"message_reply_to_sender_sent_a_voice_message"];
- _senderSentAFile = [NSBundle mxk_localizedStringForKey:@"message_reply_to_sender_sent_a_file"];
- _messageToReplyToPrefix = [NSBundle mxk_localizedStringForKey:@"message_reply_to_message_to_reply_to_prefix"];
- }
- return self;
-}
-
-@end

diff:
+/*
+ Copyright 2018 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/Foundation.h>
+#import <MatrixSDK/MXSendReplyEventStringLocalizer.h>
+
+/**
+ A `MXKSendReplyEventStringLocalizer` instance represents string localizations used when send reply event to a message in a room.
+ */
+@interface MXKSendReplyEventStringLocalizer : NSObject<MXSendReplyEventStringLocalizer>
+
+@end

diff:
+/*
+ Copyright 2018 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 "MXKSendReplyEventStringLocalizer.h"
+#import "MXKSwiftHeader.h"
+
+@implementation MXKSendReplyEventStringLocalizer
+
+- (NSString *)senderSentAnImage
+{
+ return [MatrixKitL10n messageReplyToSenderSentAnImage];
+}
+
+- (NSString *)senderSentAVideo
+{
+ return [MatrixKitL10n messageReplyToSenderSentAVideo];
+}
+
+- (NSString *)senderSentAnAudioFile
+{
+ return [MatrixKitL10n messageReplyToSenderSentAnAudioFile];
+}
+
+- (NSString *)senderSentAVoiceMessage
+{
+ return [MatrixKitL10n messageReplyToSenderSentAVoiceMessage];
+}
+
+- (NSString *)senderSentAFile
+{
+ return [MatrixKitL10n messageReplyToSenderSentAFile];
+}
+
+- (NSString *)messageToReplyToPrefix
+{
+ return [MatrixKitL10n messageReplyToMessageToReplyToPrefix];
+}
+
+@end

diff:
#import "MXKTools.h"
#import "MXRoom+Sync.h"
-#import "MXKRoomNameStringLocalizations.h"
+#import "MXKRoomNameStringLocalizer.h"
static NSString *const kHTMLATagRegexPattern = @"([^<]*)";
@@ -101,7 +101,7 @@ static NSString *const kHTMLATagRegexPattern = @"([^<]*)";
defaultRoomSummaryUpdater = [MXRoomSummaryUpdater roomSummaryUpdaterForSession:matrixSession];
defaultRoomSummaryUpdater.ignoreMemberProfileChanges = YES;
defaultRoomSummaryUpdater.ignoreRedactedEvent = !_settings.showRedactionsInRoomHistory;
- defaultRoomSummaryUpdater.roomNameStringLocalizations = [MXKRoomNameStringLocalizations new];
+ defaultRoomSummaryUpdater.roomNameStringLocalizer = [MXKRoomNameStringLocalizer new];
linkDetector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypeLink error:nil];

diff:
-/*
- Copyright 2018 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 "MXKRoomNameStringLocalizations.h"
-
-#import "NSBundle+MatrixKit.h"
-
-#import "MXKSwiftHeader.h"
-
-@interface MXKRoomNameStringLocalizations ()
-
-@property (nonatomic, copy) NSString *emptyRoom;
-@property (nonatomic, copy) NSString *twoMembers;
-@property (nonatomic, copy) NSString *moreThanTwoMembers;
-@property (nonatomic, copy) NSString *allOtherParticipantsLeft;
-
-@end
-
-@implementation MXKRoomNameStringLocalizations
-
-- (instancetype)init
-{
- self = [super init];
- if (self)
- {
- _emptyRoom = [MatrixKitL10n roomDisplaynameEmptyRoom];
- _twoMembers = [NSBundle mxk_localizedStringForKey:@"room_displayname_two_members"];
- _moreThanTwoMembers = [NSBundle mxk_localizedStringForKey:@"room_displayname_more_than_two_members"];
- _allOtherParticipantsLeft = [NSBundle mxk_localizedStringForKey:@"room_displayname_all_other_participants_left"];
- }
- return self;
-}
-
-@end

change_type: RENAME

diff:
@import Foundation;
-#import <MatrixSDK/MXRoomNameStringsLocalizable.h>
+#import <MatrixSDK/MXRoomNameStringLocalizer.h>
/**
- The `MXKRoomNameStringLocalizations` implements localization strings for `MXRoomNameStringsLocalizable`.
+ The `MXKRoomNameStringLocalizer` implements localization strings for `MXRoomNameStringLocalizable`.
*/
-@interface MXKRoomNameStringLocalizations : NSObject <MXRoomNameStringsLocalizable>
+@interface MXKRoomNameStringLocalizer : NSObject <MXRoomNameStringLocalizer>
@end

diff:
+/*
+ Copyright 2018 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 "MXKRoomNameStringLocalizer.h"
+#import "MXKSwiftHeader.h"
+
+@implementation MXKRoomNameStringLocalizer
+
+- (NSString *)emptyRoom
+{
+ return [MatrixKitL10n roomDisplaynameEmptyRoom];
+}
+
+- (NSString *)twoMembers:(NSString *)firstMember second:(NSString *)secondMember
+{
+ return [MatrixKitL10n roomDisplaynameTwoMembers:firstMember :secondMember];
+}
+
+- (NSString *)moreThanTwoMembers:(NSString *)firstMember count:(NSNumber *)memberCount
+{
+ return [MatrixKitL10n roomDisplaynameMoreThanTwoMembers:firstMember :memberCount.stringValue];
+}
+
+- (NSString *)allOtherMembersLeft:(NSString *)member
+{
+ return [MatrixKitL10n roomDisplaynameAllOtherMembersLeft:member];
+}
+
+@end


message: vector-im/element-ios/issues/4899 - Localized and generated missing strings.

diff:
"ssl_unexpected_existing_expl" = "The certificate has changed from one that was trusted by your phone. This is HIGHLY UNUSUAL. It is recommended that you DO NOT ACCEPT this new certificate.";
"ssl_expected_existing_expl" = "The certificate has changed from a previously trusted one to one that is not trusted. The server may have renewed its certificate. Contact the server administrator for the expected fingerprint.";
"ssl_only_accept" = "ONLY accept the certificate if the server administrator has published a fingerprint that matches the one above.";
+
+"auth_invalid_user_name" = "Invalid username";
+"auth_username_in_use" = "Username in use";
+"auth_reset_password_error_unauthorized" = "Unauthorized";
+"auth_reset_password_error_not_found" = "Not found";

diff:
if (isUserNameInUse)
{
MXLogDebug(@"[MXKAuthenticationVC] User name is already use");
- [self onFailureDuringAuthRequest:[NSError errorWithDomain:MXKAuthErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey:[NSBundle mxk_localizedStringForKey:@"auth_username_in_use"]}]];
+ [self onFailureDuringAuthRequest:[NSError errorWithDomain:MXKAuthErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey:[MatrixKitL10n authUsernameInUse]}]];
}
else
{
else
{
MXLogDebug(@"[MXKAuthenticationVC] User name is missing");
- [self onFailureDuringAuthRequest:[NSError errorWithDomain:MXKAuthErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey:[NSBundle mxk_localizedStringForKey:@"auth_invalid_user_name"]}]];
+ [self onFailureDuringAuthRequest:[NSError errorWithDomain:MXKAuthErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey:[MatrixKitL10n authInvalidUserName]}]];
}
}
else if (_authType == MXKAuthenticationTypeForgotPassword)
[self->alert dismissViewControllerAnimated:NO completion:nil];
}
- self->alert = [UIAlertController alertControllerWithTitle:[MatrixKitL10n error] message:[NSBundle mxk_localizedStringForKey:@"auth_reset_password_error_unauthorized"] preferredStyle:UIAlertControllerStyleAlert];
+ self->alert = [UIAlertController alertControllerWithTitle:[MatrixKitL10n error] message:[MatrixKitL10n authResetPasswordErrorUnauthorized] preferredStyle:UIAlertControllerStyleAlert];
[self->alert addAction:[UIAlertAction actionWithTitle:[MatrixKitL10n ok]
style:UIAlertActionStyleDefault
{
userInfo = [NSMutableDictionary dictionary];
}
- userInfo[NSLocalizedDescriptionKey] = [NSBundle mxk_localizedStringForKey:@"auth_reset_password_error_not_found"];
+ userInfo[NSLocalizedDescriptionKey] = [MatrixKitL10n authResetPasswordErrorNotFound];
[self onFailureDuringAuthRequest:[NSError errorWithDomain:kMXNSErrorDomain code:0 userInfo:userInfo]];
}

diff:
@@ -159,6 +159,22 @@ public class MatrixKitL10n: NSObject {
public static func attachmentSmallWithResolution(_ p1: String, _ p2: String) -> String {
return MatrixKitL10n.tr("attachment_small_with_resolution", p1, p2)
}
+ /// Invalid username
+ public static var authInvalidUserName: String {
+ return MatrixKitL10n.tr("auth_invalid_user_name")
+ }
+ /// Not found
+ public static var authResetPasswordErrorNotFound: String {
+ return MatrixKitL10n.tr("auth_reset_password_error_not_found")
+ }
+ /// Unauthorized
+ public static var authResetPasswordErrorUnauthorized: String {
+ return MatrixKitL10n.tr("auth_reset_password_error_unauthorized")
+ }
+ /// Username in use
+ public static var authUsernameInUse: String {
+ return MatrixKitL10n.tr("auth_username_in_use")
+ }
/// Back
public static var back: String {
return MatrixKitL10n.tr("back")

diff:
@@ -1736,7 +1736,7 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
NSString *sanitizedText = [self sanitizedMessageText:text];
NSString *html = [self htmlMessageFromSanitizedText:sanitizedText];
- id<MXSendReplyEventStringLocalizer> stringLocalizer = [MXKSendReplyEventStringLocalizer new];
+ id<MXSendReplyEventStringLocalizerProtocol> stringLocalizer = [MXKSendReplyEventStringLocalizer new];
[_room sendReplyToEvent:eventToReply withTextMessage:sanitizedText formattedTextMessage:html stringLocalizer:stringLocalizer localEcho:&localEchoEvent success:success failure:failure];

diff:
*/
#import <Foundation/Foundation.h>
-#import <MatrixSDK/MXSendReplyEventStringLocalizer.h>
+#import <MatrixSDK/MXSendReplyEventStringLocalizerProtocol.h>
/**
A `MXKSendReplyEventStringLocalizer` instance represents string localizations used when send reply event to a message in a room.
*/
-@interface MXKSendReplyEventStringLocalizer : NSObject<MXSendReplyEventStringLocalizer>
+@interface MXKSendReplyEventStringLocalizer : NSObject<MXSendReplyEventStringLocalizerProtocol>
@end

diff:
@import Foundation;
-#import <MatrixSDK/MXRoomNameStringLocalizer.h>
+#import <MatrixSDK/MXRoomNameStringLocalizerProtocol.h>
/**
- The `MXKRoomNameStringLocalizer` implements localization strings for `MXRoomNameStringLocalizable`.
+ The `MXKRoomNameStringLocalizer` implements localization strings for `MXRoomNameStringLocalizerProtocol`.
*/
-@interface MXKRoomNameStringLocalizer : NSObject <MXRoomNameStringLocalizer>
+@interface MXKRoomNameStringLocalizer : NSObject <MXRoomNameStringLocalizerProtocol>
@end

diff:
+Replaced localizable strings with generated ones throughout the code. Fixed various translation issues.
\ No newline at end of file


message: vector-im/element-ios/issues/4899 - MXKEventFormatter: Fixed invalid parameters passed to generated localization functions.

diff:
@@ -997,11 +997,11 @@ static NSString *const kHTMLATagRegexPattern = @"([^<]*)";
{
if (isRoomDirect)
{
- displayText = [MatrixKitL10n noticeRoomAliasesForDm:aliases];
+ displayText = [MatrixKitL10n noticeRoomAliasesForDm:[aliases componentsJoinedByString:@", "]];
}
else
{
- displayText = [MatrixKitL10n noticeRoomAliases:aliases];
+ displayText = [MatrixKitL10n noticeRoomAliases:[aliases componentsJoinedByString:@", "]];
}
// Append redacted info if any
if (redactedInfo)
@@ -1017,7 +1017,7 @@ static NSString *const kHTMLATagRegexPattern = @"([^<]*)";
MXJSONModelSetArray(groups, event.content[@"groups"]);
if (groups)
{
- displayText = [MatrixKitL10n noticeRoomRelatedGroups:groups];
+ displayText = [MatrixKitL10n noticeRoomRelatedGroups:[groups componentsJoinedByString:@", "]];
// Append redacted info if any
if (redactedInfo)
{

diff:
+MXKEventFormatter: Fixed invalid parameters passed to generated localization functions.
\ No newline at end of file


message: vector-im/element-ios/issues/5009 - Fixed MXKAttachment prepareShare being prematurely deleted when original file name is missing.

diff:
@@ -671,6 +671,7 @@ NSString *const kMXKAttachmentFileNameBase = @"attatchment";
if ([[NSFileManager defaultManager] copyItemAtPath:path toPath:self->documentCopyPath error:nil])
{
fileUrl = [NSURL fileURLWithPath:self->documentCopyPath];
+ [[NSFileManager defaultManager] removeItemAtPath:path error:nil];
}
}
@@ -678,6 +679,7 @@ NSString *const kMXKAttachmentFileNameBase = @"attatchment";
{
// Use the cached file by default
fileUrl = [NSURL fileURLWithPath:path];
+ self->documentCopyPath = path;
}
onReadyToShare (fileUrl);
@@ -687,7 +689,6 @@ NSString *const kMXKAttachmentFileNameBase = @"attatchment";
{
[self decryptToTempFile:^(NSString *path) {
haveFile(path);
- [[NSFileManager defaultManager] removeItemAtPath:path error:nil];
} failure:onFailure];
}
else


message: vector-im/element-ios/issues/5009 - Added video, url and fileUrl constants to MXKUTI.swift.

diff:
@@ -164,10 +164,13 @@ extension MXKUTI {
public static let data = MXKUTI(cfRawValue: kUTTypeData)!
public static let text = MXKUTI(cfRawValue: kUTTypeText)!
public static let audio = MXKUTI(cfRawValue: kUTTypeAudio)!
+ public static let video = MXKUTI(cfRawValue: kUTTypeVideo)!
public static let movie = MXKUTI(cfRawValue: kUTTypeMovie)!
public static let image = MXKUTI(cfRawValue: kUTTypeImage)!
public static let png = MXKUTI(cfRawValue: kUTTypePNG)!
public static let jpeg = MXKUTI(cfRawValue: kUTTypeJPEG)!
+ public static let url = MXKUTI(cfRawValue: kUTTypeURL)!
+ public static let fileUrl = MXKUTI(cfRawValue: kUTTypeFileURL)!
}
// MARK: - Convenients static methods