Merge remote-tracking branch 'origin/develop' into develop

This commit is contained in:
Weblate 2017-10-17 08:23:56 +00:00
commit 54ebef8c53
36 changed files with 1703 additions and 335 deletions

View file

@ -1,3 +1,57 @@
Changes in 0.5.6 (2017-10-05)
===============================================
Improvements:
* Settings: Pin rooms with missed notifs and unread msg by default (PR #1556).
Bug Fix:
* Fix RAM peak usage when doing an initial sync with large rooms (PR #1553).
Changes in 0.5.5 (2017-10-04)
===============================================
Improvements:
* Rageshake: Add a setting to enable (disable) it (PR #1552).
Bug Fix:
* Some rooms have gone nameless after upgrade (PR #1551).
Changes in 0.5.4 (2017-10-03)
===============================================
Improvements:
* Upgrade MatrixKit version (v0.6.3).
* Show the "Integrations Manager" into a webview (PR #1511).
* Widgets: list active widgets in a room (#1535).
* Jitsi widget: Add notices for jitsi widget in rooms histories (PR #1488).
* Add screen for incoming calls, thanks to @morozkin (PR #1477).
* Update strings for push notifications, thanks to @morozkin (PR #1486).
* Handle the room display name and its avatar at the room summary level (PR #1510).
* Create DM with Riot-bot on new account creation (vector-im/riot-meta#94).
* Add WidgetViewController (PR #1514).
* BugReportVC: Force users to add a description in crash reports (PR #1520).
* Jitsi: Enable the "Create conference calls with jitsi" settings by default (PR #1549).
Bug Fixes:
* Fix inbound video calls don't have speakerphone turned on by default (#933).
* Room settings: the displayed room access settings is wrong (#1494).
* When receiving an invite tagged as DM it's filed in rooms (#1308).
* Altering DMness of rooms is broken (#1370).
* Alert about incoming call isn't displayed (#1480), thanks to @morozkin (#1481).
* Dark theme - Improvements (#1444).
* Settings: some of the labels push the switch controls off screen (#1506).
* Settings: The "Sign out" button and other buttons of this page sometimes blinks (#1354).
* [iOS11] "Smart [colors] Invert" renders badly in the app (#1524).
* [iOS11] Room member details: the member's avatar is cropped in the header (#1531).
* [iOS11] Fix layout disruptions (PR #1537).
* Return key on hardware keyboards now sends messages, thanks to @vivlim (PR #1513).
* MediaPickerViewController: Add sanity checks to avoid crashes (#1532).
* RoomsViewController: Crash in [RoomsViewController prepareForSegue:… (#1533).
Translations:
* Enable Basque, thanks to @osoitz.
* Enable Simplified Chinese, thanks to @tonghuix (Note: the push notifications are not translated yet).
Changes in 0.5.3 (2017-08-25)
===============================================

34
Podfile
View file

@ -5,10 +5,9 @@ source 'https://github.com/CocoaPods/Specs.git'
target "Riot" do
# Different flavours of pods to MatrixKit
# The tagged version on which this version of Riot has been built
pod 'MatrixKit', '0.6.2'
pod 'MatrixKit', '0.6.3'
# The lastest release available on the CocoaPods repository
#pod 'MatrixKit'
@ -53,7 +52,7 @@ pod 'OLMKit'
pod 'Realm', '~> 2.10.2'
# The tagged version on which this version of Riot share extension has been built
pod 'MatrixKit/AppExtension', '0.6.2'
pod 'MatrixKit/AppExtension', '0.6.3'
# The lastest release available on the CocoaPods repository
#pod 'MatrixKit/AppExtension'
@ -74,5 +73,34 @@ pod 'cmark', :inhibit_warnings => true
end
target "SiriIntents" do
pod 'GoogleAnalytics'
# The Google WebRTC stack
pod 'WebRTC', '58.17.16937'
# OLMKit for crypto
pod 'OLMKit'
#pod 'OLMKit', :path => '../olm/OLMKit.podspec'
pod 'Realm', '~> 2.10.2'
# The tagged version on which this version of Riot share extension has been built
pod 'MatrixKit/AppExtension', '0.6.3'
# The lastest release available on the CocoaPods repository
#pod 'MatrixKit/AppExtension'
# The develop branch version
#pod 'MatrixSDK', :git => 'https://github.com/matrix-org/matrix-ios-sdk.git', :branch => 'develop'
#pod 'MatrixKit/AppExtension', :git => 'https://github.com/matrix-org/matrix-ios-kit.git', :branch => 'develop'
# The one used for developing both MatrixSDK and MatrixKit
# Note that MatrixSDK must be cloned into a folder called matrix-ios-sdk next to the MatrixKit folder
#pod 'MatrixSDK', :path => '../matrix-ios-sdk/MatrixSDK.podspec'
#pod 'MatrixKit/AppExtension', :path => '../matrix-ios-kit/MatrixKit.podspec'
# Remove warnings from "bad" pods
pod 'OLMKit', :inhibit_warnings => true
pod 'cmark', :inhibit_warnings => true
end

View file

@ -37,34 +37,34 @@ PODS:
- DTFoundation/Core
- DTFoundation/UIKit (1.7.12):
- DTFoundation/Core
- GBDeviceInfo (4.3.0):
- GBDeviceInfo/Core (= 4.3.0)
- GBDeviceInfo/Core (4.3.0)
- GBDeviceInfo (4.4.0):
- GBDeviceInfo/Core (= 4.4.0)
- GBDeviceInfo/Core (4.4.0)
- GoogleAnalytics (3.17.0)
- GZIP (1.1.1)
- HPGrowingTextView (1.1)
- libPhoneNumber-iOS (0.9.10)
- MatrixKit (0.6.2):
- MatrixKit (0.6.3):
- cmark (~> 0.24.1)
- DTCoreText (~> 1.6.17)
- HPGrowingTextView (~> 1.1)
- libPhoneNumber-iOS (~> 0.9.10)
- MatrixKit/Core (= 0.6.2)
- MatrixSDK (= 0.9.2)
- MatrixKit/AppExtension (0.6.2):
- MatrixKit/Core (= 0.6.3)
- MatrixSDK (= 0.9.3)
- MatrixKit/AppExtension (0.6.3):
- cmark (~> 0.24.1)
- DTCoreText (~> 1.6.17)
- DTCoreText/Extension
- HPGrowingTextView (~> 1.1)
- libPhoneNumber-iOS (~> 0.9.10)
- MatrixSDK (= 0.9.2)
- MatrixKit/Core (0.6.2):
- MatrixSDK (= 0.9.3)
- MatrixKit/Core (0.6.3):
- cmark (~> 0.24.1)
- DTCoreText (~> 1.6.17)
- HPGrowingTextView (~> 1.1)
- libPhoneNumber-iOS (~> 0.9.10)
- MatrixSDK (= 0.9.2)
- MatrixSDK (0.9.2):
- MatrixSDK (= 0.9.3)
- MatrixSDK (0.9.3):
- AFNetworking (~> 3.1.0)
- GZIP (~> 1.1.1)
- OLMKit (2.2.2):
@ -72,20 +72,20 @@ PODS:
- OLMKit/olmcpp (= 2.2.2)
- OLMKit/olmc (2.2.2)
- OLMKit/olmcpp (2.2.2)
- Realm (2.8.3):
- Realm/Headers (= 2.8.3)
- Realm/Headers (2.8.3)
- Realm (2.10.2):
- Realm/Headers (= 2.10.2)
- Realm/Headers (2.10.2)
- WebRTC (58.17.16937)
DEPENDENCIES:
- cmark
- DTCoreText
- GBDeviceInfo (~> 4.3.0)
- GBDeviceInfo (~> 4.4.0)
- GoogleAnalytics
- MatrixKit (= 0.6.2)
- MatrixKit/AppExtension (= 0.6.2)
- MatrixKit (= 0.6.3)
- MatrixKit/AppExtension (= 0.6.3)
- OLMKit
- Realm (~> 2.8.1)
- Realm (~> 2.10.2)
- WebRTC (= 58.17.16937)
SPEC CHECKSUMS:
@ -93,17 +93,17 @@ SPEC CHECKSUMS:
cmark: ec0275215b504780287b6fca360224e384368af8
DTCoreText: e5d688cffc9f6a61eddd1a4f94e2046851230de3
DTFoundation: 26a164ef510877387906fb92bff524a792db4bf8
GBDeviceInfo: caae36532afcc209b51ac62bba547aadab9e88f2
GBDeviceInfo: 2ec90c6808d063061b16773ec8e857257058dc5d
GoogleAnalytics: f42cc53a87a51fe94334821868d9c8481ff47a7b
GZIP: f8beb59597f651e6970a45b816508a9c6d700b77
HPGrowingTextView: 88a716d97fb853bcb08a4a08e4727da17efc9b19
libPhoneNumber-iOS: f721ae4d5854bce60934f9fb9b0b28e8e68913cb
MatrixKit: 8552ee8abf935b08ae08fc0000f53ab3218ea5a0
MatrixSDK: 0499dd3dbe293ce1e743a7cda181dcf50eda7f10
MatrixKit: 98a10c8127edb32e0e402d4b9535aea3397e2caa
MatrixSDK: 834a8a059de81a967404b04086a4abe28456f49a
OLMKit: b9d8c0ffee9ea8c45bc0aaa9afb47f93fba7efbd
Realm: 3601ef091c8c499a31101d8563b991e75546cdce
Realm: 0ef72b837fb67e9f4b098bac771ddd72c7fdbb69
WebRTC: 1e9a85bf75509eec44be6478c64e9de65ac82332
PODFILE CHECKSUM: db0ae7d6037f7768feb2adf17119ba69d9e1a77b
PODFILE CHECKSUM: f14b066c880bcf6d8d97d536d8e70df07eb72cc1
COCOAPODS: 1.3.1

276
Riot.xcodeproj/project.pbxproj Normal file → Executable file
View file

@ -29,7 +29,7 @@
24EEE5A11F23A09A00B3C705 /* RiotDesignValues.m in Sources */ = {isa = PBXBuildFile; fileRef = F083BC171E7009EC00A9B29C /* RiotDesignValues.m */; };
24EEE5A21F23A8B400B3C705 /* MXRoom+Riot.m in Sources */ = {isa = PBXBuildFile; fileRef = F083BBE81E7009EC00A9B29C /* MXRoom+Riot.m */; };
24EEE5A31F23A8C300B3C705 /* AvatarGenerator.m in Sources */ = {isa = PBXBuildFile; fileRef = F083BC111E7009EC00A9B29C /* AvatarGenerator.m */; };
24EEE5A41F24C06E00B3C705 /* BuildFile in Resources */ = {isa = PBXBuildFile; };
24EEE5A41F24C06E00B3C705 /* (null) in Resources */ = {isa = PBXBuildFile; };
24EEE5A81F25529600B3C705 /* cancel@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = F0614A121EDEE65000F5DC9A /* cancel@3x.png */; };
24EEE5A91F25529900B3C705 /* cancel@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = F0614A111EDEE65000F5DC9A /* cancel@2x.png */; };
24EEE5AA1F25529C00B3C705 /* cancel.png in Resources */ = {isa = PBXBuildFile; fileRef = F0614A101EDEE65000F5DC9A /* cancel.png */; };
@ -84,12 +84,22 @@
32F3AE1A1F6FF4E600F0F004 /* WidgetViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F3AE191F6FF4E600F0F004 /* WidgetViewController.m */; };
32FD0A3D1EB0CD9B0072B066 /* BugReportViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 32FD0A3B1EB0CD9B0072B066 /* BugReportViewController.m */; };
32FD0A3E1EB0CD9B0072B066 /* BugReportViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 32FD0A3C1EB0CD9B0072B066 /* BugReportViewController.xib */; };
714F6391AC0AA86C0AEB3F43 /* libPods-SiriIntents.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5666C1236223F54D4C635C54 /* libPods-SiriIntents.a */; };
83711A7C1F6F8E7D008F0D4D /* KeyboardGrowingTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = 83711A7B1F6F8E7D008F0D4D /* KeyboardGrowingTextView.m */; };
92324BE31F4F66D3009DE194 /* IncomingCallView.m in Sources */ = {isa = PBXBuildFile; fileRef = 92324BE21F4F66D3009DE194 /* IncomingCallView.m */; };
92324BE61F4F6A60009DE194 /* CircleButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 92324BE51F4F6A60009DE194 /* CircleButton.m */; };
926FA53F1F4C132000F826C2 /* MXSession+Riot.m in Sources */ = {isa = PBXBuildFile; fileRef = 926FA53E1F4C132000F826C2 /* MXSession+Riot.m */; };
92726A471F58737A004AD26F /* IntentHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 92726A461F58737A004AD26F /* IntentHandler.m */; };
92726A4B1F58737A004AD26F /* SiriIntents.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 92726A431F58737A004AD26F /* SiriIntents.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
92726A511F587410004AD26F /* Intents.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 92726A501F587410004AD26F /* Intents.framework */; };
A27ECCE3FC4971745D2CB78D /* libPods-RiotShareExtension.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7246451C668D6782166E22EC /* libPods-RiotShareExtension.a */; };
F0131DE51F2200D600CBF707 /* RiotSplitViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = F0131DE41F2200D600CBF707 /* RiotSplitViewController.m */; };
F02C1A861E8EB04C0045A404 /* PeopleViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = F02C1A841E8EB04C0045A404 /* PeopleViewController.m */; };
F04AF26A1F83A4C100D20F4D /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = F04AF25F1F83A4C000D20F4D /* InfoPlist.strings */; };
F04AF26B1F83A4C100D20F4D /* Vector.strings in Resources */ = {isa = PBXBuildFile; fileRef = F04AF2611F83A4C000D20F4D /* Vector.strings */; };
F04AF26C1F83A4C100D20F4D /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = F04AF2641F83A4C000D20F4D /* InfoPlist.strings */; };
F04AF26D1F83A4C100D20F4D /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = F04AF2661F83A4C000D20F4D /* Localizable.strings */; };
F04AF26E1F83A4C100D20F4D /* Vector.strings in Resources */ = {isa = PBXBuildFile; fileRef = F04AF2681F83A4C000D20F4D /* Vector.strings */; };
F05BD79E1E7AEBF800C69941 /* UnifiedSearchViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = F05BD79D1E7AEBF800C69941 /* UnifiedSearchViewController.m */; };
F05BD7A11E7C0E4500C69941 /* MasterTabBarController.m in Sources */ = {isa = PBXBuildFile; fileRef = F05BD7A01E7C0E4500C69941 /* MasterTabBarController.m */; };
F0614A0D1EDDCCE700F5DC9A /* jump_to_unread.png in Resources */ = {isa = PBXBuildFile; fileRef = F0614A0A1EDDCCE700F5DC9A /* jump_to_unread.png */; };
@ -550,6 +560,13 @@
remoteGlobalIDString = 24CBEC4D1F0EAD310093EABB;
remoteInfo = "Riot Share Extension";
};
92726A491F58737A004AD26F /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = F094A99A1B78D8F000B1FBBF /* Project object */;
proxyType = 1;
remoteGlobalIDString = 92726A421F58737A004AD26F;
remoteInfo = SiriIntents;
};
F094A9BF1B78D8F000B1FBBF /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = F094A99A1B78D8F000B1FBBF /* Project object */;
@ -567,6 +584,7 @@
dstSubfolderSpec = 13;
files = (
24CBEC591F0EAD310093EABB /* RiotShareExtension.appex in Embed App Extensions */,
92726A4B1F58737A004AD26F /* SiriIntents.appex in Embed App Extensions */,
);
name = "Embed App Extensions";
runOnlyForDeploymentPostprocessing = 0;
@ -673,6 +691,9 @@
32FD0A3A1EB0CD9B0072B066 /* BugReportViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BugReportViewController.h; sourceTree = "<group>"; };
32FD0A3B1EB0CD9B0072B066 /* BugReportViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BugReportViewController.m; sourceTree = "<group>"; };
32FD0A3C1EB0CD9B0072B066 /* BugReportViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = BugReportViewController.xib; sourceTree = "<group>"; };
397BCA987893439918EBF330 /* Pods-SiriIntents.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SiriIntents.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SiriIntents/Pods-SiriIntents.debug.xcconfig"; sourceTree = "<group>"; };
4D1164C2F07EF74950DCDA7A /* Pods-SiriIntents.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SiriIntents.release.xcconfig"; path = "Pods/Target Support Files/Pods-SiriIntents/Pods-SiriIntents.release.xcconfig"; sourceTree = "<group>"; };
5666C1236223F54D4C635C54 /* libPods-SiriIntents.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-SiriIntents.a"; sourceTree = BUILT_PRODUCTS_DIR; };
7246451C668D6782166E22EC /* libPods-RiotShareExtension.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-RiotShareExtension.a"; sourceTree = BUILT_PRODUCTS_DIR; };
765F5104DB3EC39713DEB3A4 /* Pods-RiotShareExtension.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RiotShareExtension.release.xcconfig"; path = "Pods/Target Support Files/Pods-RiotShareExtension/Pods-RiotShareExtension.release.xcconfig"; sourceTree = "<group>"; };
83711A7B1F6F8E7D008F0D4D /* KeyboardGrowingTextView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KeyboardGrowingTextView.m; sourceTree = "<group>"; };
@ -681,11 +702,24 @@
92324BE21F4F66D3009DE194 /* IncomingCallView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IncomingCallView.m; sourceTree = "<group>"; };
92324BE41F4F6A60009DE194 /* CircleButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CircleButton.h; sourceTree = "<group>"; };
92324BE51F4F6A60009DE194 /* CircleButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CircleButton.m; sourceTree = "<group>"; };
926FA53D1F4C132000F826C2 /* MXSession+Riot.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MXSession+Riot.h"; sourceTree = "<group>"; };
926FA53E1F4C132000F826C2 /* MXSession+Riot.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MXSession+Riot.m"; sourceTree = "<group>"; };
92726A431F58737A004AD26F /* SiriIntents.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = SiriIntents.appex; sourceTree = BUILT_PRODUCTS_DIR; };
92726A451F58737A004AD26F /* IntentHandler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IntentHandler.h; sourceTree = "<group>"; };
92726A461F58737A004AD26F /* IntentHandler.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IntentHandler.m; sourceTree = "<group>"; };
92726A481F58737A004AD26F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
92726A4F1F587393004AD26F /* SiriIntents.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = SiriIntents.entitlements; sourceTree = "<group>"; };
92726A501F587410004AD26F /* Intents.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Intents.framework; path = System/Library/Frameworks/Intents.framework; sourceTree = SDKROOT; };
C195C53961EA28E6900AEB68 /* Pods-Riot.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Riot.release.xcconfig"; path = "Pods/Target Support Files/Pods-Riot/Pods-Riot.release.xcconfig"; sourceTree = "<group>"; };
F0131DE31F2200D600CBF707 /* RiotSplitViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RiotSplitViewController.h; sourceTree = "<group>"; };
F0131DE41F2200D600CBF707 /* RiotSplitViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RiotSplitViewController.m; sourceTree = "<group>"; };
F02C1A831E8EB04C0045A404 /* PeopleViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PeopleViewController.h; sourceTree = "<group>"; };
F02C1A841E8EB04C0045A404 /* PeopleViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PeopleViewController.m; sourceTree = "<group>"; };
F04AF2601F83A4C000D20F4D /* zh_Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = zh_Hans; path = InfoPlist.strings; sourceTree = "<group>"; };
F04AF2621F83A4C000D20F4D /* zh_Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = zh_Hans; path = Vector.strings; sourceTree = "<group>"; };
F04AF2651F83A4C000D20F4D /* eu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = eu; path = InfoPlist.strings; sourceTree = "<group>"; };
F04AF2671F83A4C000D20F4D /* eu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = eu; path = Localizable.strings; sourceTree = "<group>"; };
F04AF2691F83A4C000D20F4D /* eu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = eu; path = Vector.strings; sourceTree = "<group>"; };
F05BD79C1E7AEBF800C69941 /* UnifiedSearchViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UnifiedSearchViewController.h; sourceTree = "<group>"; };
F05BD79D1E7AEBF800C69941 /* UnifiedSearchViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UnifiedSearchViewController.m; sourceTree = "<group>"; };
F05BD79F1E7C0E4500C69941 /* MasterTabBarController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MasterTabBarController.h; sourceTree = "<group>"; };
@ -1270,6 +1304,15 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
92726A401F58737A004AD26F /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
92726A511F587410004AD26F /* Intents.framework in Frameworks */,
714F6391AC0AA86C0AEB3F43 /* libPods-SiriIntents.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
F094A99F1B78D8F000B1FBBF /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
@ -1460,8 +1503,10 @@
5FC42FA41F5186AFFB6A2404 /* Frameworks */ = {
isa = PBXGroup;
children = (
92726A501F587410004AD26F /* Intents.framework */,
FD9D0BDE9232898950554DD5 /* libPods-Riot.a */,
7246451C668D6782166E22EC /* libPods-RiotShareExtension.a */,
5666C1236223F54D4C635C54 /* libPods-SiriIntents.a */,
);
name = Frameworks;
sourceTree = "<group>";
@ -1473,6 +1518,8 @@
C195C53961EA28E6900AEB68 /* Pods-Riot.release.xcconfig */,
12AA0005C8B3D8D8162584C5 /* Pods-RiotShareExtension.debug.xcconfig */,
765F5104DB3EC39713DEB3A4 /* Pods-RiotShareExtension.release.xcconfig */,
397BCA987893439918EBF330 /* Pods-SiriIntents.debug.xcconfig */,
4D1164C2F07EF74950DCDA7A /* Pods-SiriIntents.release.xcconfig */,
);
name = Pods;
sourceTree = "<group>";
@ -1488,6 +1535,36 @@
path = Calls;
sourceTree = "<group>";
};
92726A441F58737A004AD26F /* SiriIntents */ = {
isa = PBXGroup;
children = (
92726A4F1F587393004AD26F /* SiriIntents.entitlements */,
92726A451F58737A004AD26F /* IntentHandler.h */,
92726A461F58737A004AD26F /* IntentHandler.m */,
92726A481F58737A004AD26F /* Info.plist */,
);
path = SiriIntents;
sourceTree = "<group>";
};
F04AF25E1F83A4C000D20F4D /* zh_Hans.lproj */ = {
isa = PBXGroup;
children = (
F04AF25F1F83A4C000D20F4D /* InfoPlist.strings */,
F04AF2611F83A4C000D20F4D /* Vector.strings */,
);
path = zh_Hans.lproj;
sourceTree = "<group>";
};
F04AF2631F83A4C000D20F4D /* eu.lproj */ = {
isa = PBXGroup;
children = (
F04AF2641F83A4C000D20F4D /* InfoPlist.strings */,
F04AF2661F83A4C000D20F4D /* Localizable.strings */,
F04AF2681F83A4C000D20F4D /* Vector.strings */,
);
path = eu.lproj;
sourceTree = "<group>";
};
F083BB021E7005FD00A9B29C /* RiotTests */ = {
isa = PBXGroup;
children = (
@ -1539,6 +1616,8 @@
F083BB0E1E7009EC00A9B29C /* Assets */ = {
isa = PBXGroup;
children = (
F04AF2631F83A4C000D20F4D /* eu.lproj */,
F04AF25E1F83A4C000D20F4D /* zh_Hans.lproj */,
32918EA41F473BDB0076CA16 /* ru.lproj */,
327382A71F276AD200356143 /* de.lproj */,
327382BB1F276AED00356143 /* en.lproj */,
@ -1819,6 +1898,8 @@
F083BBEA1E7009EC00A9B29C /* UINavigationController+Riot.m */,
F083BBEB1E7009EC00A9B29C /* UIViewController+RiotSearch.h */,
F083BBEC1E7009EC00A9B29C /* UIViewController+RiotSearch.m */,
926FA53D1F4C132000F826C2 /* MXSession+Riot.h */,
926FA53E1F4C132000F826C2 /* MXSession+Riot.m */,
);
path = Categories;
sourceTree = "<group>";
@ -2355,6 +2436,7 @@
F083BB081E7009EC00A9B29C /* Riot */,
F083BB021E7005FD00A9B29C /* RiotTests */,
24CBEC4F1F0EAD310093EABB /* RiotShareExtension */,
92726A441F58737A004AD26F /* SiriIntents */,
F094A9A31B78D8F000B1FBBF /* Products */,
7471DF3720D498384A068DA7 /* Pods */,
5FC42FA41F5186AFFB6A2404 /* Frameworks */,
@ -2367,6 +2449,7 @@
F094A9A21B78D8F000B1FBBF /* Riot.app */,
F094A9BE1B78D8F000B1FBBF /* RiotTests.xctest */,
24CBEC4E1F0EAD310093EABB /* RiotShareExtension.appex */,
92726A431F58737A004AD26F /* SiriIntents.appex */,
);
name = Products;
sourceTree = "<group>";
@ -2403,6 +2486,25 @@
productReference = 24CBEC4E1F0EAD310093EABB /* RiotShareExtension.appex */;
productType = "com.apple.product-type.app-extension";
};
92726A421F58737A004AD26F /* SiriIntents */ = {
isa = PBXNativeTarget;
buildConfigurationList = 92726A4E1F58737A004AD26F /* Build configuration list for PBXNativeTarget "SiriIntents" */;
buildPhases = (
6AA0024D4D5FAE30C2E1F311 /* [CP] Check Pods Manifest.lock */,
92726A3F1F58737A004AD26F /* Sources */,
92726A401F58737A004AD26F /* Frameworks */,
92726A411F58737A004AD26F /* Resources */,
807A0ABF153A23C2FC22F977 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
dependencies = (
);
name = SiriIntents;
productName = SiriIntents;
productReference = 92726A431F58737A004AD26F /* SiriIntents.appex */;
productType = "com.apple.product-type.app-extension";
};
F094A9A11B78D8F000B1FBBF /* Riot */ = {
isa = PBXNativeTarget;
buildConfigurationList = F094A9C81B78D8F000B1FBBF /* Build configuration list for PBXNativeTarget "Riot" */;
@ -2420,6 +2522,7 @@
);
dependencies = (
242661F61F12B1BA00D3FC08 /* PBXTargetDependency */,
92726A4A1F58737A004AD26F /* PBXTargetDependency */,
);
name = Riot;
productName = Vector;
@ -2463,6 +2566,16 @@
};
};
};
92726A421F58737A004AD26F = {
CreatedOnToolsVersion = 8.3.3;
DevelopmentTeam = 7J4U792NQT;
ProvisioningStyle = Automatic;
SystemCapabilities = {
com.apple.ApplicationGroups.iOS = {
enabled = 1;
};
};
};
F094A9A11B78D8F000B1FBBF = {
CreatedOnToolsVersion = 6.2;
DevelopmentTeam = 7J4U792NQT;
@ -2494,6 +2607,8 @@
de,
fr,
ru,
zh_Hans,
eu,
);
mainGroup = F094A9991B78D8F000B1FBBF;
productRefGroup = F094A9A31B78D8F000B1FBBF /* Products */;
@ -2503,6 +2618,7 @@
F094A9A11B78D8F000B1FBBF /* Riot */,
F094A9BD1B78D8F000B1FBBF /* RiotTests */,
24CBEC4D1F0EAD310093EABB /* RiotShareExtension */,
92726A421F58737A004AD26F /* SiriIntents */,
);
};
/* End PBXProject section */
@ -2526,9 +2642,16 @@
24EEE5AA1F25529C00B3C705 /* cancel.png in Resources */,
F0A895601F7D404B00BD6C2A /* e2e_verified.png in Resources */,
24D6B35E1F3CA03E00FC7A71 /* FallbackViewController.xib in Resources */,
24EEE5A41F24C06E00B3C705 /* BuildFile in Resources */,
24EEE5A41F24C06E00B3C705 /* (null) in Resources */,
2439DD641F6BBEA50090F42D /* RecentRoomTableViewCell.xib in Resources */,
24EEE5A41F24C06E00B3C705 /* BuildFile in Resources */,
24EEE5A41F24C06E00B3C705 /* (null) in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
92726A411F58737A004AD26F /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -2601,6 +2724,7 @@
F083BD991E7009ED00A9B29C /* logo@2x.png in Resources */,
F083BD331E7009ED00A9B29C /* call_audio_mute_off_icon.png in Resources */,
F083BD691E7009ED00A9B29C /* directChatOn@2x.png in Resources */,
F04AF26E1F83A4C100D20F4D /* Vector.strings in Resources */,
F083BD3E1E7009ED00A9B29C /* call_hangup_icon@3x.png in Resources */,
32AE61F21F0D2183007255F4 /* InfoPlist.strings in Resources */,
F083BDB91E7009ED00A9B29C /* remove_icon_pink.png in Resources */,
@ -2633,6 +2757,7 @@
F0E05A3D1EA0F9EB004B83FB /* tab_people_selected@2x.png in Resources */,
F0E05A451EA0F9EB004B83FB /* tab_rooms.png in Resources */,
F083BE751E7009ED00A9B29C /* RoomOutgoingTextMsgWithoutSenderNameBubbleCell.xib in Resources */,
F04AF26A1F83A4C100D20F4D /* InfoPlist.strings in Resources */,
F083BD261E7009ED00A9B29C /* admin_icon@2x.png in Resources */,
3205ED851E97725E003D65FA /* DirectoryServerTableViewCell.xib in Resources */,
F083BD761E7009ED00A9B29C /* e2e_verified@3x.png in Resources */,
@ -2722,6 +2847,7 @@
F083BDB41E7009ED00A9B29C /* priorityLow@2x.png in Resources */,
F083BD671E7009ED00A9B29C /* directChatOff@3x.png in Resources */,
F083BE791E7009ED00A9B29C /* RoomOutgoingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.xib in Resources */,
F04AF26C1F83A4C100D20F4D /* InfoPlist.strings in Resources */,
F0E05A321EA0F9EB004B83FB /* tab_favourites_selected@3x.png in Resources */,
F083BD4D1E7009ED00A9B29C /* camera_capture@3x.png in Resources */,
F083BDB11E7009ED00A9B29C /* priorityHigh@2x.png in Resources */,
@ -2735,6 +2861,7 @@
F083BE831E7009ED00A9B29C /* RecentTableViewCell.xib in Resources */,
F083BDB71E7009ED00A9B29C /* remove_icon@2x.png in Resources */,
F083BDD31E7009ED00A9B29C /* settings_icon@3x.png in Resources */,
F04AF26B1F83A4C100D20F4D /* Vector.strings in Resources */,
F083BDBA1E7009ED00A9B29C /* remove_icon_pink@2x.png in Resources */,
F083BDC91E7009ED00A9B29C /* search_icon@2x.png in Resources */,
F083BE381E7009ED00A9B29C /* RoomActivitiesView.xib in Resources */,
@ -2858,6 +2985,7 @@
F083BD221E7009ED00A9B29C /* add_participant.png in Resources */,
F083BDC61E7009ED00A9B29C /* search_bg@2x.png in Resources */,
F083BD421E7009ED00A9B29C /* call_speaker_on_icon.png in Resources */,
F04AF26D1F83A4C100D20F4D /* Localizable.strings in Resources */,
F083BD9A1E7009ED00A9B29C /* logo@3x.png in Resources */,
327382BA1F276AD200356143 /* Vector.strings in Resources */,
327382C41F276AED00356143 /* Vector.strings in Resources */,
@ -3003,7 +3131,7 @@
"${PODS_ROOT}/MatrixKit/MatrixKit/Views/RoomTitle/MXKRoomTitleView.xib",
"${PODS_ROOT}/MatrixKit/MatrixKit/Views/RoomTitle/MXKRoomTitleViewWithTopic.xib",
"${PODS_ROOT}/MatrixKit/MatrixKit/Views/Search/MXKSearchTableViewCell.xib",
"$PODS_CONFIGURATION_BUILD_DIR/MatrixKit/MatrixKit.bundle",
$PODS_CONFIGURATION_BUILD_DIR/MatrixKit/MatrixKit.bundle,
"${PODS_ROOT}/MatrixSDK/MatrixSDK/Data/Store/MXCoreDataStore/MXCoreDataStore.xcdatamodeld",
);
name = "[CP] Copy Pods Resources";
@ -3015,6 +3143,24 @@
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Riot/Pods-Riot-resources.sh\"\n";
showEnvVarsInLog = 0;
};
6AA0024D4D5FAE30C2E1F311 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-SiriIntents-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
7FFD40AA75DB32D83350D225 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
@ -3033,6 +3179,24 @@
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Riot/Pods-Riot-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
807A0ABF153A23C2FC22F977 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${SRCROOT}/Pods/Target Support Files/Pods-SiriIntents/Pods-SiriIntents-resources.sh",
"${PODS_ROOT}/MatrixSDK/MatrixSDK/Data/Store/MXCoreDataStore/MXCoreDataStore.xcdatamodeld",
);
name = "[CP] Copy Pods Resources";
outputPaths = (
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SiriIntents/Pods-SiriIntents-resources.sh\"\n";
showEnvVarsInLog = 0;
};
8EA19F5011654D3BD5EDAC33 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
@ -3075,6 +3239,14 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
92726A3F1F58737A004AD26F /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
92726A471F58737A004AD26F /* IntentHandler.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
F094A99E1B78D8F000B1FBBF /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
@ -3200,6 +3372,7 @@
F083BDF81E7009ED00A9B29C /* RoomDataSource.m in Sources */,
F083BE371E7009ED00A9B29C /* RoomActivitiesView.m in Sources */,
F083BE131E7009ED00A9B29C /* HomeMessagesSearchViewController.m in Sources */,
926FA53F1F4C132000F826C2 /* MXSession+Riot.m in Sources */,
F083BE8C1E7009ED00A9B29C /* PreviewRoomTitleView.m in Sources */,
F083BE271E7009ED00A9B29C /* SettingsViewController.m in Sources */,
F083BE9A1E7009ED00A9B29C /* TableViewCellWithButton.m in Sources */,
@ -3244,6 +3417,11 @@
target = 24CBEC4D1F0EAD310093EABB /* RiotShareExtension */;
targetProxy = 242661F51F12B1BA00D3FC08 /* PBXContainerItemProxy */;
};
92726A4A1F58737A004AD26F /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 92726A421F58737A004AD26F /* SiriIntents */;
targetProxy = 92726A491F58737A004AD26F /* PBXContainerItemProxy */;
};
F094A9C01B78D8F000B1FBBF /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = F094A9A11B78D8F000B1FBBF /* Riot */;
@ -3372,6 +3550,46 @@
name = Vector.strings;
sourceTree = "<group>";
};
F04AF25F1F83A4C000D20F4D /* InfoPlist.strings */ = {
isa = PBXVariantGroup;
children = (
F04AF2601F83A4C000D20F4D /* zh_Hans */,
);
name = InfoPlist.strings;
sourceTree = "<group>";
};
F04AF2611F83A4C000D20F4D /* Vector.strings */ = {
isa = PBXVariantGroup;
children = (
F04AF2621F83A4C000D20F4D /* zh_Hans */,
);
name = Vector.strings;
sourceTree = "<group>";
};
F04AF2641F83A4C000D20F4D /* InfoPlist.strings */ = {
isa = PBXVariantGroup;
children = (
F04AF2651F83A4C000D20F4D /* eu */,
);
name = InfoPlist.strings;
sourceTree = "<group>";
};
F04AF2661F83A4C000D20F4D /* Localizable.strings */ = {
isa = PBXVariantGroup;
children = (
F04AF2671F83A4C000D20F4D /* eu */,
);
name = Localizable.strings;
sourceTree = "<group>";
};
F04AF2681F83A4C000D20F4D /* Vector.strings */ = {
isa = PBXVariantGroup;
children = (
F04AF2691F83A4C000D20F4D /* eu */,
);
name = Vector.strings;
sourceTree = "<group>";
};
F083BBE21E7009EC00A9B29C /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
@ -3428,6 +3646,47 @@
};
name = Release;
};
92726A4C1F58737A004AD26F /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 397BCA987893439918EBF330 /* Pods-SiriIntents.debug.xcconfig */;
buildSettings = {
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CODE_SIGN_ENTITLEMENTS = SiriIntents/SiriIntents.entitlements;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = 7J4U792NQT;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = SiriIntents/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = im.vector.app.SiriIntents;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
};
name = Debug;
};
92726A4D1F58737A004AD26F /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 4D1164C2F07EF74950DCDA7A /* Pods-SiriIntents.release.xcconfig */;
buildSettings = {
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CODE_SIGN_ENTITLEMENTS = SiriIntents/SiriIntents.entitlements;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = 7J4U792NQT;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = SiriIntents/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = im.vector.app.SiriIntents;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
};
name = Release;
};
F094A9C61B78D8F000B1FBBF /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
@ -3608,6 +3867,15 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
92726A4E1F58737A004AD26F /* Build configuration list for PBXNativeTarget "SiriIntents" */ = {
isa = XCConfigurationList;
buildConfigurations = (
92726A4C1F58737A004AD26F /* Debug */,
92726A4D1F58737A004AD26F /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
F094A99D1B78D8F000B1FBBF /* Build configuration list for PBXProject "Riot" */ = {
isa = XCConfigurationList;
buildConfigurations = (

View file

@ -109,7 +109,11 @@ static RageShakeManager* sharedInstance = nil;
- (void)startShaking:(UIResponder*)responder {
// Start only if the application is in foreground
if ([AppDelegate theDelegate].isAppForeground && !confirmationAlert) {
// And if the rageshake user setting is enabled
if ([AppDelegate theDelegate].isAppForeground
&& [[NSUserDefaults standardUserDefaults] boolForKey:@"enableRageShake"]
&& !confirmationAlert)
{
NSLog(@"[RageShakeManager] Start shaking with [%@]", [responder class]);
startShakingTimeStamp = [[NSDate date] timeIntervalSince1970];
@ -129,18 +133,6 @@ static RageShakeManager* sharedInstance = nil;
confirmationAlert = [UIAlertController alertControllerWithTitle:NSLocalizedStringFromTable(@"rage_shake_prompt", @"Vector", nil) message:nil preferredStyle:UIAlertControllerStyleAlert];
__weak typeof(self) weakSelf = self;
[confirmationAlert addAction:[UIAlertAction actionWithTitle:[NSBundle mxk_localizedStringForKey:@"cancel"]
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
if (weakSelf)
{
typeof(self) self = weakSelf;
self->confirmationAlert = nil;
}
}]];
[confirmationAlert addAction:[UIAlertAction actionWithTitle:[NSBundle mxk_localizedStringForKey:@"ok"]
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
@ -161,6 +153,34 @@ static RageShakeManager* sharedInstance = nil;
}]];
[confirmationAlert addAction:[UIAlertAction actionWithTitle:[NSBundle mxk_localizedStringForKey:@"do_not_ask_again"]
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
if (weakSelf)
{
typeof(self) self = weakSelf;
self->confirmationAlert = nil;
// Disable rageshake user setting
[[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"enableRageShake"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
}]];
[confirmationAlert addAction:[UIAlertAction actionWithTitle:[NSBundle mxk_localizedStringForKey:@"cancel"]
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
if (weakSelf)
{
typeof(self) self = weakSelf;
self->confirmationAlert = nil;
}
}]];
[(UIViewController*)responder presentViewController:confirmationAlert animated:YES completion:nil];
}
}

View file

@ -43,7 +43,7 @@ extern NSString *const kAppDelegateNetworkStatusDidChangeNotification;
@interface AppDelegate : UIResponder <UIApplicationDelegate, MXKCallViewControllerDelegate, UISplitViewControllerDelegate, UINavigationControllerDelegate, JitsiViewControllerDelegate>
{
BOOL isAPNSRegistered;
BOOL isPushRegistered;
// background sync management
void (^_completionHandler)(UIBackgroundFetchResult);
@ -112,7 +112,7 @@ extern NSString *const kAppDelegateNetworkStatusDidChangeNotification;
- (void)startGoogleAnalytics;
- (void)stopGoogleAnalytics;
#pragma mark - APNS methods
#pragma mark - Push notifications
- (void)registerUserNotificationSettings;

View file

@ -17,6 +17,9 @@
#import "AppDelegate.h"
#import <Intents/Intents.h>
#import <PushKit/PushKit.h>
#import "RecentsDataSource.h"
#import "RoomDataSource.h"
@ -40,8 +43,17 @@
#import <AudioToolbox/AudioToolbox.h>
#include <MatrixSDK/MXUIKitBackgroundModeHandler.h>
// Calls
#import "CallViewController.h"
#import <MatrixSDK/MXCallKitAdapter.h>
#import <MatrixSDK/MXCallKitConfiguration.h>
#import "MXSession+Riot.h"
#import "MXRoom+Riot.h"
//#define MX_CALL_STACK_OPENWEBRTC
#ifdef MX_CALL_STACK_OPENWEBRTC
#import <MatrixOpenWebRTCWrapper/MatrixOpenWebRTCWrapper.h>
@ -51,9 +63,10 @@
#import <MatrixEndpointWrapper/MatrixEndpointWrapper.h>
#endif
#include <MatrixSDK/MXJingleCallStack.h>
#include <MatrixSDK/MXUIKitBackgroundModeHandler.h>
#ifdef MX_CALL_STACK_JINGLE
#import <MatrixSDK/MXJingleCallStack.h>
#import <MatrixSDK/MXJingleCallAudioSessionConfigurator.h>
#endif
#define CALL_STATUS_BAR_HEIGHT 44
@ -63,7 +76,7 @@
NSString *const kAppDelegateDidTapStatusBarNotification = @"kAppDelegateDidTapStatusBarNotification";
NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateNetworkStatusDidChangeNotification";
@interface AppDelegate ()
@interface AppDelegate () <PKPushRegistryDelegate>
{
/**
Reachability observer
@ -106,11 +119,6 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN
*/
NSMutableArray *mxSessionArray;
/**
The room id of the current handled remote notification (if any)
*/
NSString *remoteNotificationRoomId;
/**
The fragment of the universal link being processing.
Only one fragment is handled at a time.
@ -147,6 +155,13 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN
*/
NSMutableDictionary *callEventsListeners;
/**
The notification listener blocks.
There is one block per MXSession.
The key is an identifier of the MXSession. The value, the listener block.
*/
NSMutableDictionary <NSNumber *, MXOnNotification> *notificationListenerBlocks;
/**
Currently displayed "Call not supported" alert.
*/
@ -165,9 +180,14 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN
}
@property (strong, nonatomic) UIAlertController *mxInAppNotification;
@property (strong, nonatomic) UIAlertController *incomingCallNotification;
@property (nonatomic, nullable, copy) void (^registrationForRemoteNotificationsCompletion)(NSError *);
@property (nonatomic, strong) PKPushRegistry *pushRegistry;
@property (nonatomic) BOOL hasPendingLocalNotifications;
@end
@implementation AppDelegate
@ -307,6 +327,7 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN
mxSessionArray = [NSMutableArray array];
callEventsListeners = [NSMutableDictionary dictionary];
notificationListenerBlocks = [NSMutableDictionary dictionary];
// To simplify navigation into the app, we retrieve here the main navigation controller and the tab bar controller.
UISplitViewController *splitViewController = (UISplitViewController *)self.window.rootViewController;
@ -443,13 +464,6 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
// cancel any background sync before resuming
// i.e. warn IOS that there is no new data with any received push.
[self cancelBackgroundSync];
// Open account session(s) if this is not already done (see [initMatrixSessions] in case of background launch).
[[MXKAccountManager sharedManager] prepareSessionForActiveAccounts];
_isAppForeground = YES;
// GA: Start a new session. The next hit from this tracker will be the first in a new session.
@ -460,7 +474,7 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN
{
NSLog(@"[AppDelegate] applicationDidBecomeActive");
remoteNotificationRoomId = nil;
_hasPendingLocalNotifications = NO;
// Check if there is crash log to send
if ([[NSUserDefaults standardUserDefaults] boolForKey:@"enableCrashReport"])
@ -534,6 +548,11 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN
[self stopGoogleAnalytics];
}
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application
{
NSLog(@"[AppDelegate] applicationDidReceiveMemoryWarning");
}
- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray * _Nullable))restorationHandler
{
BOOL continueUserActivity = NO;
@ -542,6 +561,67 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN
{
continueUserActivity = [self handleUniversalLink:userActivity];
}
else if ([userActivity.activityType isEqualToString:INStartAudioCallIntentIdentifier] ||
[userActivity.activityType isEqualToString:INStartVideoCallIntentIdentifier])
{
INInteraction *interaction = userActivity.interaction;
// roomID provided by Siri intent
NSString *roomID = userActivity.userInfo[@"roomID"];
// We've launched from calls history list
if (!roomID)
{
INPerson *person;
if ([interaction.intent isKindOfClass:INStartAudioCallIntent.class])
{
person = [[(INStartAudioCallIntent *)(interaction.intent) contacts] firstObject];
}
else if ([interaction.intent isKindOfClass:INStartVideoCallIntent.class])
{
person = [[(INStartVideoCallIntent *)(interaction.intent) contacts] firstObject];
}
roomID = person.personHandle.value;
}
BOOL isVideoCall = [userActivity.activityType isEqualToString:INStartVideoCallIntentIdentifier];
UIApplication *application = UIApplication.sharedApplication;
NSNumber *backgroundTaskIdentifier;
// Start background task since we need time for MXSession preparasion because our app can be launched in the background
if (application.applicationState == UIApplicationStateBackground)
backgroundTaskIdentifier = @([application beginBackgroundTaskWithExpirationHandler:^{}]);
MXSession *session = mxSessionArray.firstObject;
[session.callManager placeCallInRoom:roomID
withVideo:isVideoCall
success:^(MXCall *call) {
if (application.applicationState == UIApplicationStateBackground)
{
__weak NSNotificationCenter *center = NSNotificationCenter.defaultCenter;
__block id token =
[center addObserverForName:kMXCallStateDidChange
object:call
queue:nil
usingBlock:^(NSNotification * _Nonnull note) {
if (call.state == MXCallStateEnded)
{
[application endBackgroundTask:backgroundTaskIdentifier.unsignedIntegerValue];
[center removeObserver:token];
}
}];
}
}
failure:^(NSError *error) {
if (backgroundTaskIdentifier)
[application endBackgroundTask:backgroundTaskIdentifier.unsignedIntegerValue];
}];
continueUserActivity = YES;
}
return continueUserActivity;
}
@ -885,11 +965,11 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN
}
}
#pragma mark - APNS methods
#pragma mark - Push notifications
- (void)registerUserNotificationSettings
{
if (!isAPNSRegistered)
if (!isPushRegistered)
{
// Registration on iOS 8 and later
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeBadge | UIUserNotificationTypeSound |UIUserNotificationTypeAlert) categories:nil];
@ -900,7 +980,10 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN
- (void)registerForRemoteNotificationsWithCompletion:(nullable void (^)(NSError *))completion
{
self.registrationForRemoteNotificationsCompletion = completion;
[[UIApplication sharedApplication] registerForRemoteNotifications];
self.pushRegistry = [[PKPushRegistry alloc] initWithQueue:nil];
self.pushRegistry.delegate = self;
self.pushRegistry.desiredPushTypes = [NSSet setWithObject:PKPushTypeVoIP];
}
- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
@ -914,58 +997,15 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN
{
// Clear existing token
MXKAccountManager* accountManager = [MXKAccountManager sharedManager];
[accountManager setApnsDeviceToken:nil];
[accountManager setPushDeviceToken:nil withPushOptions:nil];
}
}
- (void)application:(UIApplication*)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{
NSUInteger len = ((deviceToken.length > 8) ? 8 : deviceToken.length / 2);
NSLog(@"[AppDelegate] Got APNS token! (%@ ...)", [deviceToken subdataWithRange:NSMakeRange(0, len)]);
NSLog(@"[AppDelegate] didReceiveLocalNotification: applicationState: %@", @([UIApplication sharedApplication].applicationState));
MXKAccountManager* accountManager = [MXKAccountManager sharedManager];
[accountManager setApnsDeviceToken:deviceToken];
isAPNSRegistered = YES;
if (self.registrationForRemoteNotificationsCompletion)
{
self.registrationForRemoteNotificationsCompletion(nil);
self.registrationForRemoteNotificationsCompletion = nil;
}
}
- (void)application:(UIApplication*)app didFailToRegisterForRemoteNotificationsWithError:(NSError*)error
{
NSLog(@"[AppDelegate] Failed to register for APNS: %@", error);
if (self.registrationForRemoteNotificationsCompletion)
{
self.registrationForRemoteNotificationsCompletion(error);
self.registrationForRemoteNotificationsCompletion = nil;
}
}
- (void)cancelBackgroundSync
{
if (_completionHandler)
{
_completionHandler(UIBackgroundFetchResultNoData);
_completionHandler = nil;
}
}
- (void)application:(UIApplication*)application didReceiveRemoteNotification:(NSDictionary*)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
#ifdef DEBUG
// log the full userInfo only in DEBUG
NSLog(@"[AppDelegate] didReceiveRemoteNotification: %@", userInfo);
#else
NSLog(@"[AppDelegate] didReceiveRemoteNotification");
#endif
// Look for the room id
NSString* roomId = [userInfo objectForKey:@"room_id"];
NSString* roomId = notification.userInfo[@"room_id"];
if (roomId.length)
{
// TODO retrieve the right matrix session
@ -995,71 +1035,186 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN
// sanity checks
if (dedicatedAccount && dedicatedAccount.mxSession)
{
UIApplicationState state = [UIApplication sharedApplication].applicationState;
// Jump to the concerned room only if the app is transitioning from the background
if (state == UIApplicationStateInactive)
{
// Check whether another remote notification is not already processed
if (!remoteNotificationRoomId)
{
remoteNotificationRoomId = roomId;
NSLog(@"[AppDelegate] didReceiveRemoteNotification: open the roomViewController %@", roomId);
NSLog(@"[AppDelegate] didReceiveLocalNotification: open the roomViewController %@", roomId);
[self showRoom:roomId andEventId:nil withMatrixSession:dedicatedAccount.mxSession];
}
else
{
NSLog(@"[AppDelegate] didReceiveRemoteNotification: busy");
NSLog(@"[AppDelegate] didReceiveLocalNotification : no linked session / account has been found.");
}
}
else if (!_completionHandler && (state == UIApplicationStateBackground))
}
- (void)pushRegistry:(PKPushRegistry *)registry didUpdatePushCredentials:(PKPushCredentials *)credentials forType:(PKPushType)type
{
NSData *token = credentials.token;
NSUInteger len = ((token.length > 8) ? 8 : token.length / 2);
NSLog(@"[AppDelegate] Got Push token! (%@ ...)", [token subdataWithRange:NSMakeRange(0, len)]);
MXKAccountManager* accountManager = [MXKAccountManager sharedManager];
[accountManager setPushDeviceToken:token withPushOptions:@{@"format": @"event_id_only"}];
isPushRegistered = YES;
if (self.registrationForRemoteNotificationsCompletion)
{
_completionHandler = completionHandler;
NSLog(@"[AppDelegate] didReceiveRemoteNotification: starts a background sync");
[dedicatedAccount backgroundSync:20000 success:^{
NSLog(@"[AppDelegate] didReceiveRemoteNotification: the background sync succeeds");
if (_completionHandler)
{
_completionHandler(UIBackgroundFetchResultNewData);
_completionHandler = nil;
self.registrationForRemoteNotificationsCompletion(nil);
self.registrationForRemoteNotificationsCompletion = nil;
}
} failure:^(NSError *error) {
NSLog(@"[AppDelegate] didReceiveRemoteNotification: the background sync fails");
}
if (_completionHandler)
{
_completionHandler(UIBackgroundFetchResultNoData);
_completionHandler = nil;
}
}];
- (void)pushRegistry:(PKPushRegistry *)registry didInvalidatePushTokenForType:(PKPushType)type
{
MXKAccountManager* accountManager = [MXKAccountManager sharedManager];
[accountManager setPushDeviceToken:nil withPushOptions:nil];
}
// wait that the background sync is done
- (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(PKPushType)type
{
// Handle the local notifications by triggering a background sync.
[self handleLocalNotifications];
}
- (void)handleLocalNotifications
{
_hasPendingLocalNotifications = NO;
// Check whether the application is running in background.
if ([UIApplication sharedApplication].applicationState != UIApplicationStateBackground)
return;
// Launch a background sync for all existing matrix sessions
NSArray *mxAccounts = [MXKAccountManager sharedManager].activeAccounts;
for (MXKAccount *account in mxAccounts)
{
// Check the current session state
if (account.mxSession.state != MXSessionStatePaused)
{
NSLog(@"[AppDelegate] handleLocalNotifications: delay the background sync");
// Turn on the flag used to trigger a new background sync when a session is paused.
_hasPendingLocalNotifications = YES;
}
[account backgroundSync:20000 success:^{
NSLog(@"[AppDelegate] handleLocalNotifications: the background sync succeeds");
// Update icon badge number
[UIApplication sharedApplication].applicationIconBadgeNumber = [account.mxSession riot_missedDiscussionsCount];
} failure:^(NSError *error) {
NSLog(@"[AppDelegate] handleLocalNotifications: the background sync fails");
}];
}
}
- (nullable NSString *)notificationBodyForEvent:(MXEvent *)event withRoomState:(MXRoomState *)roomState pushRule:(MXPushRule*)rule inAccount:(MXKAccount*)account
{
if (!event.content || !event.content.count)
return nil;
NSString *notificationBody;
NSString *eventSenderName = [roomState memberName:event.sender];
if (event.eventType == MXEventTypeRoomMessage || event.eventType == MXEventTypeRoomEncrypted)
{
MXRoom *room = [account.mxSession roomWithRoomId:event.roomId];
if (room.isMentionsOnly)
{
// A local notification will be displayed only for highlighted notification.
BOOL isHighlighted = NO;
// Check whether is there an highlight tweak on it
for (MXPushRuleAction *ruleAction in rule.actions)
{
if (ruleAction.actionType == MXPushRuleActionTypeSetTweak)
{
if ([ruleAction.parameters[@"set_tweak"] isEqualToString:@"highlight"])
{
// Check the highlight tweak "value"
// If not present, highlight. Else check its value before highlighting
if (nil == ruleAction.parameters[@"value"] || YES == [ruleAction.parameters[@"value"] boolValue])
{
isHighlighted = YES;
break;
}
}
}
}
if (!isHighlighted)
{
// Ignore this notif.
return nil;
}
}
NSString *msgType = event.content[@"msgtype"];
NSString *content = event.content[@"body"];
if (event.isEncrypted && !account.showDecryptedContentInNotifications)
{
// Hide the content
msgType = nil;
}
NSString *roomDisplayName = room.summary.displayname;
// Display the room name only if it is different than the sender name
if (roomDisplayName.length && ![roomDisplayName isEqualToString:eventSenderName])
{
if ([msgType isEqualToString:@"m.text"])
notificationBody = [NSString stringWithFormat:NSLocalizedString(@"MSG_FROM_USER_IN_ROOM_WITH_CONTENT", nil), eventSenderName,roomDisplayName, content];
else if ([msgType isEqualToString:@"m.emote"])
notificationBody = [NSString stringWithFormat:NSLocalizedString(@"ACTION_FROM_USER_IN_ROOM", nil), roomDisplayName, eventSenderName, content];
else if ([msgType isEqualToString:@"m.image"])
notificationBody = [NSString stringWithFormat:NSLocalizedString(@"IMAGE_FROM_USER_IN_ROOM", nil), eventSenderName, content, roomDisplayName];
else
// Encrypted messages falls here
notificationBody = [NSString stringWithFormat:NSLocalizedString(@"MSG_FROM_USER_IN_ROOM", nil), eventSenderName, roomDisplayName];
}
else
{
NSLog(@"[AppDelegate] didReceiveRemoteNotification : no linked session / account has been found.");
if ([msgType isEqualToString:@"m.text"])
notificationBody = [NSString stringWithFormat:NSLocalizedString(@"MSG_FROM_USER_WITH_CONTENT", nil), eventSenderName, content];
else if ([msgType isEqualToString:@"m.emote"])
notificationBody = [NSString stringWithFormat:NSLocalizedString(@"ACTION_FROM_USER", nil), eventSenderName, content];
else if ([msgType isEqualToString:@"m.image"])
notificationBody = [NSString stringWithFormat:NSLocalizedString(@"IMAGE_FROM_USER", nil), eventSenderName, content];
else
// Encrypted messages falls here
notificationBody = [NSString stringWithFormat:NSLocalizedString(@"MSG_FROM_USER", nil), eventSenderName];
}
}
completionHandler(UIBackgroundFetchResultNoData);
}
else if (event.eventType == MXEventTypeCallInvite)
{
NSString *sdp = event.content[@"offer"][@"sdp"];
BOOL isVideoCall = [sdp rangeOfString:@"m=video"].location != NSNotFound;
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
// iOS 10 (at least up to GM beta release) does not call application:didReceiveRemoteNotification:fetchCompletionHandler:
// when the user clicks on a notification but it calls this deprecated version
// of didReceiveRemoteNotification.
// Use this method as a workaround as adviced at http://stackoverflow.com/a/39419245
NSLog(@"[AppDelegate] didReceiveRemoteNotification (deprecated version)");
if (!isVideoCall)
notificationBody = [NSString stringWithFormat:NSLocalizedString(@"VOICE_CALL_FROM_USER", nil), eventSenderName];
else
notificationBody = [NSString stringWithFormat:NSLocalizedString(@"VIDEO_CALL_FROM_USER", nil), eventSenderName];
}
else if (event.eventType == MXEventTypeRoomMember)
{
NSString *roomName = roomState.name;
NSString *roomAlias = roomState.aliases.firstObject;
[self application:application didReceiveRemoteNotification:userInfo fetchCompletionHandler:^(UIBackgroundFetchResult result) {
}];
if (roomName)
notificationBody = [NSString stringWithFormat:NSLocalizedString(@"USER_INVITE_TO_NAMED_ROOM", nil), eventSenderName, roomName];
else if (roomAlias)
notificationBody = [NSString stringWithFormat:NSLocalizedString(@"USER_INVITE_TO_NAMED_ROOM", nil), eventSenderName, roomAlias];
else
notificationBody = [NSString stringWithFormat:NSLocalizedString(@"USER_INVITE_TO_CHAT", nil), eventSenderName];
}
return notificationBody;
}
- (void)refreshApplicationIconBadgeNumber
@ -1491,6 +1646,9 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN
// Get modular widget events in rooms histories
[[MXKAppSettings standardAppSettings] addSupportedEventTypes:@[kWidgetEventTypeString]];
// Use shared container to share data with app extensions
sdkOptions.applicationGroupIdentifier = @"group.im.vector";
// Disable long press on event in bubble cells
[MXKRoomBubbleTableViewCell disableLongPressGestureOnEvent:YES];
@ -1501,13 +1659,6 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN
matrixSessionStateObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXSessionStateDidChangeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
MXSession *mxSession = (MXSession*)notif.object;
// Remove by default potential call observer on matrix session state change
if (matrixCallObserver)
{
[[NSNotificationCenter defaultCenter] removeObserver:matrixCallObserver];
matrixCallObserver = nil;
}
// Check whether the concerned session is a new one
if (mxSession.state == MXSessionStateInitialised)
{
@ -1529,6 +1680,19 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN
if (callStack)
{
[mxSession enableVoIPWithCallStack:callStack];
// Setup CallKit
if ([MXCallKitAdapter callKitAvailable])
{
BOOL isCallKitEnabled = [MXKAppSettings standardAppSettings].isCallKitEnabled;
[self enableCallKit:isCallKitEnabled forCallManager:mxSession.callManager];
// Register for changes performed by the user
[[MXKAppSettings standardAppSettings] addObserver:self
forKeyPath:@"enableCallKit"
options:NSKeyValueObservingOptionNew
context:NULL];
}
}
else
{
@ -1546,12 +1710,19 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN
}
else if (mxSession.state == MXSessionStateStoreDataReady)
{
// Check whether the app user wants inApp notifications on new events for this session
// A new call observer may be added here
[self addMatrixCallObserver];
// Enable local notifications
[self enableLocalNotificationsFromMatrixSession:mxSession];
// Look for the account related to this session.
NSArray *mxAccounts = [MXKAccountManager sharedManager].activeAccounts;
for (MXKAccount *account in mxAccounts)
{
if (account.mxSession == mxSession)
{
// Enable inApp notifications (if they are allowed for this account).
[self enableInAppNotificationsForAccount:account];
break;
}
@ -1561,23 +1732,30 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN
{
[self removeMatrixSession:mxSession];
}
// Restore call observer only if all session are running
NSArray *mxSessions = self.mxSessions;
BOOL shouldAddMatrixCallObserver = (mxSessions.count);
for (mxSession in mxSessions)
// Consider here the case where the app is running in background.
else if ([[UIApplication sharedApplication] applicationState] == UIApplicationStateBackground)
{
if (mxSession.state != MXSessionStateRunning)
if (mxSession.state == MXSessionStateRunning)
{
shouldAddMatrixCallObserver = NO;
// Pause the session in background task
NSArray *mxAccounts = [MXKAccountManager sharedManager].activeAccounts;
for (MXKAccount *account in mxAccounts)
{
if (account.mxSession == mxSession)
{
[account pauseInBackgroundTask];
break;
}
}
if (shouldAddMatrixCallObserver)
}
else if (mxSession.state == MXSessionStatePaused)
{
// A new call observer may be added here
[self addMatrixCallObserver];
// Check whether some local notifications must be handled by triggering a background sync.
if (_hasPendingLocalNotifications)
{
[self handleLocalNotifications];
}
}
}
[self handleLaunchAnimation];
@ -1598,10 +1776,10 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN
// Set the push gateway URL.
account.pushGatewayURL = [[NSUserDefaults standardUserDefaults] objectForKey:@"pushGatewayURL"];
if (isAPNSRegistered)
if (isPushRegistered)
{
// Enable push notifications by default on new added account
account.enablePushNotifications = YES;
account.enablePushKitNotifications = YES;
}
else
{
@ -1668,23 +1846,20 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN
// Use MXFileStore as MXStore to permanently store events.
accountManager.storeClass = [MXFileStore class];
// Observers have been defined, we can start a matrix session for each enabled accounts.
// except if the app is still in background.
if ([[UIApplication sharedApplication] applicationState] != UIApplicationStateBackground)
// Disable APNS use.
if (accountManager.apnsDeviceToken)
{
NSLog(@"[AppDelegate] initMatrixSessions: prepareSessionForActiveAccounts");
[accountManager prepareSessionForActiveAccounts];
}
else
{
// The app is launched in background as a result of a remote notification.
// Presently we are not able to initialize the matrix session(s) in background. (FIXME: initialize matrix session(s) in case of a background launch).
// Patch: the account session(s) will be opened when the app will enter foreground.
NSLog(@"[AppDelegate] initMatrixSessions: The application has been launched in background");
// We use now Pushkit, unregister for all remote notifications received via Apple Push Notification service.
[[UIApplication sharedApplication] unregisterForRemoteNotifications];
[accountManager setApnsDeviceToken:nil];
}
// Observers have been defined, we can start a matrix session for each enabled accounts.
NSLog(@"[AppDelegate] initMatrixSessions: prepareSessionForActiveAccounts (app state: %tu)", [[UIApplication sharedApplication] applicationState]);
[accountManager prepareSessionForActiveAccounts];
// Check whether we're already logged in
NSArray *mxAccounts = accountManager.accounts;
NSArray *mxAccounts = accountManager.activeAccounts;
if (mxAccounts.count)
{
for (MXKAccount *account in mxAccounts)
@ -1751,7 +1926,16 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN
// If any, disable the no VoIP support workaround
[self disableNoVoIPOnMatrixSession:mxSession];
// Disable local notifications from this session
[self disableLocalNotificationsFromMatrixSession:mxSession];
[mxSessionArray removeObject:mxSession];
if (!mxSessionArray.count && matrixCallObserver)
{
[[NSNotificationCenter defaultCenter] removeObserver:matrixCallObserver];
matrixCallObserver = nil;
}
}
- (void)markAllMessagesAsRead
@ -1788,8 +1972,8 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN
- (void)logout
{
[[UIApplication sharedApplication] unregisterForRemoteNotifications];
isAPNSRegistered = NO;
self.pushRegistry = nil;
isPushRegistered = NO;
// Clear cache
[MXMediaManager clearCache];
@ -1828,29 +2012,142 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN
{
[self enableInAppNotificationsForAccount:(MXKAccount*)object];
}
else if (object == [MXKAppSettings standardAppSettings] && [keyPath isEqualToString:@"enableCallKit"])
{
BOOL isCallKitEnabled = [MXKAppSettings standardAppSettings].isCallKitEnabled;
MXCallManager *callManager = [[[[[MXKAccountManager sharedManager] activeAccounts] firstObject] mxSession] callManager];
[self enableCallKit:isCallKitEnabled forCallManager:callManager];
}
}
- (void)addMatrixCallObserver
{
if (matrixCallObserver)
{
[[NSNotificationCenter defaultCenter] removeObserver:matrixCallObserver];
return;
}
// Register call observer in order to handle new opened session
matrixCallObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXCallManagerNewCall object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
// Register call observer in order to handle incoming calls
matrixCallObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXCallManagerNewCall
object:nil
queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification *notif)
{
// Ignore the call if a call is already in progress
if (!currentCallViewController && !_jitsiViewController)
{
MXCall *mxCall = (MXCall*)notif.object;
BOOL isCallKitAvailable = [MXCallKitAdapter callKitAvailable] && [MXKAppSettings standardAppSettings].isCallKitEnabled;
// Prepare the call view controller
currentCallViewController = [CallViewController callViewController:mxCall];
currentCallViewController = [CallViewController callViewController:nil];
currentCallViewController.playRingtone = !isCallKitAvailable;
currentCallViewController.mxCall = mxCall;
currentCallViewController.delegate = self;
UIApplicationState applicationState = UIApplication.sharedApplication.applicationState;
// App has been woken by PushKit notification in the background
if (applicationState == UIApplicationStateBackground && mxCall.isIncoming)
{
// Create backgound task.
// Without CallKit this will allow us to play vibro until the call was ended
// With CallKit we'll inform the system when the call is ended to let the system terminate our app to save resources
id<MXBackgroundModeHandler> handler = [MXSDKOptions sharedInstance].backgroundModeHandler;
NSUInteger callTaskIdentifier = [handler startBackgroundTaskWithName:nil completion:^{}];
// Start listening for call state change notifications
__weak NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
__block id token = [[NSNotificationCenter defaultCenter] addObserverForName:kMXCallStateDidChange
object:mxCall
queue:nil
usingBlock:^(NSNotification * _Nonnull note) {
MXCall *call = (MXCall *)note.object;
if (call.state == MXCallStateEnded)
{
// Set call vc to nil to let our app handle new incoming calls even it wasn't killed by the system
currentCallViewController = nil;
[notificationCenter removeObserver:token];
[handler endBackgrounTaskWithIdentifier:callTaskIdentifier];
}
}];
}
if (mxCall.isIncoming && !isCallKitAvailable)
{
// Prompt user before presenting the call view controller
NSString *callPromptFormat = mxCall.isVideoCall ? NSLocalizedStringFromTable(@"call_incoming_video_prompt", @"Vector", nil) : NSLocalizedStringFromTable(@"call_incoming_voice_prompt", @"Vector", nil);
NSString *callerName = currentCallViewController.peer.displayname;
if (!callerName.length)
{
callerName = currentCallViewController.peer.userId;
}
NSString *callPrompt = [NSString stringWithFormat:callPromptFormat, callerName];
// Removing existing notification (if any)
[_incomingCallNotification dismissViewControllerAnimated:NO completion:nil];
_incomingCallNotification = [UIAlertController alertControllerWithTitle:callPrompt
message:nil
preferredStyle:UIAlertControllerStyleAlert];
__weak typeof(self) weakSelf = self;
[_incomingCallNotification addAction:[UIAlertAction actionWithTitle:NSLocalizedStringFromTable(@"decline", @"Vector", nil)
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
if (weakSelf)
{
typeof(self) self = weakSelf;
// Reject the call.
// Note: Do not reset the incoming call notification before this operation, because it is used to release properly the dismissed call view controller.
if (self->currentCallViewController)
{
[self->currentCallViewController onButtonPressed:self->currentCallViewController.rejectCallButton];
currentCallViewController = nil;
}
self.incomingCallNotification = nil;
mxCall.delegate = nil;
}
}]];
[_incomingCallNotification addAction:[UIAlertAction actionWithTitle:NSLocalizedStringFromTable(@"accept", @"Vector", nil)
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
if (weakSelf)
{
typeof(self) self = weakSelf;
self.incomingCallNotification = nil;
if (self->currentCallViewController)
{
[self->currentCallViewController onButtonPressed:self->currentCallViewController.answerCallButton];
[self presentCallViewController:nil];
}
}
}]];
[_incomingCallNotification mxk_setAccessibilityIdentifier:@"AppDelegateIncomingCallAlert"];
[self showNotificationAlert:_incomingCallNotification];
}
else
{
[self presentCallViewController:nil];
}
}
}];
}
@ -1956,6 +2253,105 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN
}
}
- (void)enableCallKit:(BOOL)enable forCallManager:(MXCallManager *)callManager
{
if (enable)
{
// Create adapter with default configuration for a while
MXCallKitAdapter *callKitAdapter = [[MXCallKitAdapter alloc] init];
id<MXCallAudioSessionConfigurator> audioSessionConfigurator;
#ifdef MX_CALL_STACK_JINGLE
audioSessionConfigurator = [[MXJingleCallAudioSessionConfigurator alloc] init];
#endif
callKitAdapter.audioSessionConfigurator = audioSessionConfigurator;
callManager.callKitAdapter = callKitAdapter;
}
else
{
callManager.callKitAdapter = nil;
}
}
- (void)enableLocalNotificationsFromMatrixSession:(MXSession*)mxSession
{
__weak typeof(self) weakSelf = self;
// Look for the account related to this session.
NSArray *mxAccounts = [MXKAccountManager sharedManager].activeAccounts;
MXKAccount *account;
for (account in mxAccounts)
{
if (account.mxSession == mxSession)
{
break;
}
account = nil;
}
MXOnNotification notificationListenerBlock = ^(MXEvent *event, MXRoomState *roomState, MXPushRule *rule) {
// Do not display local notification if the app is not running in background.
if ([[UIApplication sharedApplication] applicationState] != UIApplicationStateBackground)
{
return;
}
// Do not display local notifications during the initial sync.
if (!account.mxSession.isEventStreamInitialised)
{
return;
}
// For all type of event show local notifications besides the situation
// when the type of event is call invite and we have CallKit support
BOOL isCallKitActive = [MXCallKitAdapter callKitAvailable] && [MXKAppSettings standardAppSettings].isCallKitEnabled;
if (!(event.eventType == MXEventTypeCallInvite && isCallKitActive))
{
NSString *notificationBody = [weakSelf notificationBodyForEvent:event withRoomState:roomState pushRule:rule inAccount:account];
if (notificationBody)
{
UILocalNotification *eventNotification = [[UILocalNotification alloc] init];
eventNotification.fireDate = [NSDate dateWithTimeIntervalSince1970:event.originServerTs / 1000];
eventNotification.alertBody = notificationBody;
eventNotification.userInfo = @{ @"room_id" : event.roomId };
// Set sound name based on the value provided in action of MXPushRule
for (MXPushRuleAction *action in rule.actions)
{
if (action.actionType == MXPushRuleActionTypeSetTweak)
{
if ([action.parameters[@"set_tweak"] isEqualToString:@"sound"])
{
NSString *soundName = action.parameters[@"value"];
if ([soundName isEqualToString:@"default"])
soundName = UILocalNotificationDefaultSoundName;
eventNotification.soundName = soundName;
}
}
}
[[UIApplication sharedApplication] scheduleLocalNotification:eventNotification];
}
}
};
[mxSession.notificationCenter listenToNotifications:notificationListenerBlock];
notificationListenerBlocks[@(mxSession.hash)] = notificationListenerBlock;
}
- (void)disableLocalNotificationsFromMatrixSession:(MXSession*)mxSession
{
// Stop listening to notification of this session
[mxSession.notificationCenter removeListener:notificationListenerBlocks[@(mxSession.hash)]];
[notificationListenerBlocks removeObjectForKey:@(mxSession.hash)];
}
#pragma mark -
/**
@ -2037,7 +2433,6 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN
NSString* messageText = [eventFormatter stringFromEvent:event withRoomState:roomState error:&error];
if (messageText.length && (error == MXKEventFormatterErrorNone))
{
// Removing existing notification (if any)
if (self.mxInAppNotification)
{
@ -2057,8 +2452,10 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN
}
}
MXRoomSummary *roomSummary = [account.mxSession roomSummaryWithRoomId:event.roomId];
__weak typeof(self) weakSelf = self;
self.mxInAppNotification = [UIAlertController alertControllerWithTitle:roomState.displayname
self.mxInAppNotification = [UIAlertController alertControllerWithTitle:roomSummary.displayname
message:messageText
preferredStyle:UIAlertControllerStyleAlert];

View file

@ -155,6 +155,7 @@
"search_default_placeholder" = "Search";
"search_people_placeholder" = "Search by User ID, Name or email";
"search_no_result" = "No results";
"search_in_progress" = "Searching…";
// Directory
"directory_cell_title" = "Browse directory";
@ -253,7 +254,7 @@
"room_event_action_save" = "Save";
"room_event_action_resend" = "Resend";
"room_event_action_delete" = "Delete";
"room_event_action_cancel_upload" = "Cancel Upload";
"room_event_action_cancel_send" = "Cancel Send";
"room_event_action_cancel_download" = "Cancel Download";
"room_event_action_view_encryption" = "Encryption Information";
"room_warning_about_encryption" = "End-to-end encryption is in beta and may not be reliable.\n\nYou should not yet trust it to secure data.\n\nDevices will not yet be able to decrypt history from before they joined the room.\n\nEncrypted messages will not be visible on clients that do not yet implement encryption.";
@ -297,6 +298,7 @@
"settings_user_settings" = "USER SETTINGS";
"settings_notifications_settings" = "NOTIFICATION SETTINGS";
"settings_calls_settings" = "CALLS";
"settings_user_interface" = "USER INTERFACE";
"settings_ignored_users" = "IGNORED USERS";
"settings_contacts" = "LOCAL CONTACTS";
@ -326,6 +328,7 @@
"settings_fail_to_update_profile" = "Fail to update profile";
"settings_enable_push_notif" = "Notifications on this device";
"settings_show_decrypted_content" = "Show decrypted content";
"settings_global_settings_info" = "Global notification settings are available on your %@ web client";
"settings_pin_rooms_with_missed_notif" = "Pin rooms with missed notifications";
"settings_pin_rooms_with_unread" = "Pin rooms with unread messages";
@ -338,6 +341,8 @@
//"settings_join_leave_rooms" = "When people join or leave rooms";
//"settings_call_invitations" = "Call invitations";
"settings_enable_callkit" = "Integrated calling";
"settings_callkit_info" = "Receive incoming calls on your lock screen. See your Riot calls in the system's call history. If iCloud is enabled, this call history will be shared with Apple.";
"settings_ui_language" = "Language";
"settings_ui_theme" = "Theme";
"settings_ui_theme_auto" = "Auto";
@ -366,6 +371,7 @@
"settings_privacy_policy_url" = "https://riot.im/privacy";
"settings_third_party_notices" = "Third-party Notices";
"settings_send_crash_report" = "Send anon crash & usage data";
"settings_enable_rageshake" = "Rage shake to report bug";
"settings_clear_cache" = "Clear cache";
"settings_change_password" = "Change password";
@ -473,6 +479,7 @@
"public_room_section_title" = "Public Rooms (at %@):";
"bug_report_prompt" = "The application has crashed last time. Would you like to submit a crash report?";
"rage_shake_prompt" = "You seem to be shaking the phone in frustration. Would you like to submit a bug report?";
"do_not_ask_again" = "Do not ask again";
"camera_access_not_granted" = "%@ doesn't have permission to use Camera, please change privacy settings";
"large_badge_value_k_format" = "%.1fK";

View file

@ -11,9 +11,9 @@
/* New action message from a specific person in a named room. */
"ACTION_FROM_USER_IN_ROOM" = "%@: * %@ %@";
/* New action message from a specific person, not referencing a room. */
"IMAGE_FROM_USER" = "%@ erabiltzaileak irudi bat bidali dizu";
"IMAGE_FROM_USER" = "%@ erabiltzaileak irudi bat %@ bidali dizu";
/* New action message from a specific person in a named room. */
"IMAGE_FROM_USER_IN_ROOM" = "%@ erabiltzaileak irudi bat bidali du %@ gelara";
"IMAGE_FROM_USER_IN_ROOM" = "%@ erabiltzaileak irudi bat %@ bidali du %@ gelara";
/* Multiple unread messages in a room */
"UNREAD_IN_ROOM" = "%@ mezu berri %@ gelan";
/* Multiple unread messages from a specific person, not referencing a room */

View file

@ -1,5 +1,5 @@
// Permissions usage explanations
"NSCameraUsageDescription" = "La caméra est utilisée pour prendre des photos, des vidéos et passer des appels vidéo.";
"NSPhotoLibraryUsageDescription" = "La bibliothèque photo est utilisée pour envoyer des photos et des vidéos.";
"NSCameraUsageDescription" = "L'appareil photo est utilisé pour prendre des photos et des vidéos et pour passer des appels vidéo.";
"NSPhotoLibraryUsageDescription" = "La photothèque est utilisée pour envoyer des photos et des vidéos.";
"NSMicrophoneUsageDescription" = "Le microphone est utilisé pour prendre des vidéos et passer des appels.";
"NSContactsUsageDescription" = "Le carnet d'adresses est utilisé pour rechercher des utilisateurs par e-mail et numéro de téléphone sur Riot.";

View file

@ -29,7 +29,7 @@
/* Look, stuff's happened, alright? Just open the app. */
"MSGS_IN_TWO_PLUS_ROOMS" = "%@ nouveaux messages dans %@, %@ et d'autres";
/* A user has invited you to a chat */
"USER_INVITE_TO_CHAT" = "%@ vous a invité";
"USER_INVITE_TO_CHAT" = "%@ vous a invité dans une discussion";
/* A user has invited you to an (unamed) group chat */
"USER_INVITE_TO_CHAT_GROUP_CHAT" = "%@ vous a invité dans un salon";
/* A user has invited you to a named room */
@ -39,10 +39,10 @@
/* Incoming one-to-one video call */
"VIDEO_CALL_FROM_USER" = "Appel vidéo de %@";
/* Incoming unnamed voice conference invite from a specific person */
"VOICE_CONF_FROM_USER" = "Appel groupé depuis %@";
"VOICE_CONF_FROM_USER" = "Téléconférence vocale de %@";
/* Incoming unnamed video conference invite from a specific person */
"VIDEO_CONF_FROM_USER" = "Appel vidéo groupé depuis %@";
"VIDEO_CONF_FROM_USER" = "Téléconférence vidéo de %@";
/* Incoming named voice conference invite from a specific person */
"VOICE_CONF_NAMED_FROM_USER" = "Appel groupé de %@ : '%@'";
"VOICE_CONF_NAMED_FROM_USER" = "Téléconférence vocale de %@ : '%@'";
/* Incoming named video conference invite from a specific person */
"VIDEO_CONF_NAMED_FROM_USER" = "Appel vidéo groupé de %@ : '%@'";
"VIDEO_CONF_NAMED_FROM_USER" = "Téléconférence vidéo de %@ : '%@'";

View file

@ -117,6 +117,8 @@
"search_default_placeholder" = "Recherche";
"search_people_placeholder" = "Rechercher par identifiant, nom ou e-mail";
"search_no_result" = "Aucun résultat";
"search_in_progress" = "Recherche en cours…";
// Directory
"directory_cell_title" = "Parcourir le répertoire";
"directory_cell_description" = "%tu salons";
@ -210,7 +212,7 @@
"room_event_action_save" = "Enregistrer";
"room_event_action_resend" = "Renvoyer";
"room_event_action_delete" = "Supprimer";
"room_event_action_cancel_upload" = "Annuler l'envoi";
"room_event_action_cancel_send" = "Annuler l'envoi";
"room_event_action_cancel_download" = "Annuler le téléchargement";
"room_event_action_view_encryption" = "Informations sur le chiffrement";
"room_warning_about_encryption" = "Le chiffrement de bout en bout est en version bêta et peut ne pas être fiable.\n\nIl ne doit pas être considéré comme fiable pour sécuriser des données.\n\nLes appareils ne pourront pas encore déchiffrer l'historique de messages d'avant leur arrivée sur le salon.\n\nLes messages chiffrés ne seront pas visibles sur les clients qui n'ont pas encore implémenté le chiffrement.";
@ -257,7 +259,7 @@
"settings_sign_out_confirmation" = "Êtes-vous sûr(e) ?";
"settings_sign_out_e2e_warn" = "Vous perdrez vos clés de chiffrement de bout en bout. Cela signifie que vous ne pourrez plus lire les anciens messages des salons chiffrés depuis cet appareil.";
"settings_profile_picture" = "Image de profil";
"settings_display_name" = "Nom affiché";
"settings_display_name" = "Nom d'affichage";
"settings_first_name" = "Prénom";
"settings_surname" = "Nom";
"settings_remove_prompt_title" = "Confirmation";
@ -290,6 +292,7 @@
"settings_privacy_policy_url" = "https://riot.im/privacy";
"settings_third_party_notices" = "Licences tierces";
"settings_send_crash_report" = "Envoyer des rapports d'erreur anonymes et des statistiques d'utilisation";
"settings_enable_rageshake" = "Secouer l'appareil pour signaler un bug";
"settings_clear_cache" = "Vider le cache";
"settings_change_password" = "Changer de mot de passe";
"settings_old_password" = "ancien mot de passe";
@ -383,6 +386,7 @@
"public_room_section_title" = "Salons publics (sur %@) :";
"bug_report_prompt" = "L'application s'est terminée brusquement la dernière fois. Voulez-vous envoyer un rapport d'erreur ?";
"rage_shake_prompt" = "Vous semblez secouer le téléphone avec frustration. Souhaitez-vous soumettre un rapport d'erreur ?";
"do_not_ask_again" = "Ne plus demander";
"camera_access_not_granted" = "%@ n'a pas la permission pour utiliser l'appareil photo, veuillez modifier les options de vie privée";
"large_badge_value_k_format" = "%.1fK";
// room display name

View file

@ -11,9 +11,9 @@
/* New action message from a specific person in a named room. */
"ACTION_FROM_USER_IN_ROOM" = "%@* %@ %@";
/* New action message from a specific person, not referencing a room. */
"IMAGE_FROM_USER" = "%@ 傳送給您一張圖片";
"IMAGE_FROM_USER" = "%@ 傳送給您一張圖片 %@";
/* New action message from a specific person in a named room. */
"IMAGE_FROM_USER_IN_ROOM" = "%@ 貼出一張圖片在 %@";
"IMAGE_FROM_USER_IN_ROOM" = "%@ 貼出一張圖片 %@ 在 %@";
/* Multiple unread messages in a room */
"UNREAD_IN_ROOM" = "%@ 個新訊息在 %@";
/* Multiple unread messages from a specific person, not referencing a room */

View file

@ -0,0 +1,28 @@
/*
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>
#import <MatrixSDK/MXSession.h>
@interface MXSession (Riot)
/**
The current number of rooms with missed notifications, including the invites.
*/
- (NSUInteger)riot_missedDiscussionsCount;
@end

View file

@ -0,0 +1,51 @@
/*
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 "MXSession+Riot.h"
#import "MXRoom+Riot.h"
@implementation MXSession (Riot)
- (NSUInteger)riot_missedDiscussionsCount
{
NSUInteger missedDiscussionsCount = 0;
// Sum all the rooms with missed notifications.
for (MXRoomSummary *roomSummary in self.roomsSummaries)
{
NSUInteger notificationCount = roomSummary.notificationCount;
// Ignore the regular notification count if the room is in 'mentions only" mode at the Riot level.
if (roomSummary.room.isMentionsOnly)
{
// Only the highlighted missed messages must be considered here.
notificationCount = roomSummary.highlightCount;
}
if (notificationCount)
{
missedDiscussionsCount++;
}
}
// Add the invites count
missedDiscussionsCount += [self invitedRooms].count;
return missedDiscussionsCount;
}
@end

View file

@ -1,13 +1,15 @@
{
"images" : [
{
"idiom" : "iphone",
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-20@2x.png",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-20@3x.png",
"scale" : "3x"
},
{
@ -47,13 +49,15 @@
"scale" : "3x"
},
{
"idiom" : "ipad",
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-20.png",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-20@2x-1.png",
"scale" : "2x"
},
{
@ -97,6 +101,12 @@
"idiom" : "ipad",
"filename" : "Icon-83.5@2x.png",
"scale" : "2x"
},
{
"size" : "1024x1024",
"idiom" : "ios-marketing",
"filename" : "Icon-1024.png",
"scale" : "1x"
}
],
"info" : {

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

View file

@ -17,11 +17,11 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>0.5.3</string>
<string>0.5.6</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>0.5.3</string>
<string>0.5.6</string>
<key>ITSAppUsesNonExemptEncryption</key>
<true/>
<key>ITSEncryptionExportComplianceCode</key>
@ -49,6 +49,8 @@
<string>The microphone is used to take videos, make calls.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>The photo library is used to send photos and videos.</string>
<key>NSSiriUsageDescription</key>
<string>Siri is used to perform calls even from the lock screen.</string>
<key>UIBackgroundModes</key>
<array>
<string>audio</string>

View file

@ -356,9 +356,16 @@ double const kPublicRoomsDirectoryDataExpiration = 10;
}
else
{
// Show nothing while loading and in other cases
if (_searchPattern.length)
{
tableViewCell.textLabel.text = NSLocalizedStringFromTable(@"search_in_progress", @"Vector", nil);
}
else
{
// Show nothing in other cases
tableViewCell.textLabel.text = @"";
}
}
return tableViewCell;
}

View file

@ -3,15 +3,17 @@
<plist version="1.0">
<dict>
<key>pinRoomsWithMissedNotif</key>
<false/>
<true/>
<key>pinRoomsWithUnread</key>
<false/>
<true/>
<key>pushGatewayURL</key>
<string>https://matrix.org/_matrix/push/v1/notify</string>
<key>pusherAppIdDev</key>
<string>im.vector.app.ios.dev</string>
<key>pusherAppIdProd</key>
<string>im.vector.app.ios.prod</string>
<key>pushKitAppIdProd</key>
<string>im.vector.app.ios.voip.prod</string>
<key>identityserverurl</key>
<string>https://vector.im</string>
<key>homeserverurl</key>
@ -28,8 +30,6 @@
<string>https://scalar-staging.riot.im/scalar-web/</string>
<key>integrationsRestUrl</key>
<string>https://scalar-staging.riot.im/scalar/api</string>
<key>apnsDeviceToken</key>
<string></string>
<key>showAllEventsInRoomHistory</key>
<false/>
<key>showRedactionsInRoomHistory</key>
@ -42,6 +42,10 @@
<false/>
<key>syncLocalContacts</key>
<false/>
<key>createConferenceCallsWithJitsi</key>
<true/>
<key>enableRageShake</key>
<true/>
<key>maxAllowedMediaCacheSize</key>
<integer>1073741824</integer>
<key>presenceColorForOnlineUser</key>

View file

@ -11,6 +11,8 @@
<string>applinks:riot.im</string>
<string>applinks:www.riot.im</string>
</array>
<key>com.apple.developer.siri</key>
<true/>
<key>com.apple.security.application-groups</key>
<array>
<string>group.im.vector</string>

View file

@ -224,8 +224,8 @@
BOOL ret = [super session:session updateRoomSummary:summary withStateEvents:stateEvents];
// Check whether the room display name and/or the room avatar url should be updated at Riot level.
NSString *riotRoomDisplayName;
NSString *riotRoomAvatarURL;
BOOL refreshRiotRoomDisplayName = NO;
BOOL refreshRiotRoomAvatarURL = NO;
for (MXEvent *event in stateEvents)
{
@ -235,44 +235,49 @@
case MXEventTypeRoomAliases:
case MXEventTypeRoomCanonicalAlias:
{
if (!riotRoomDisplayName.length)
{
riotRoomDisplayName = [self riotRoomDisplayNameFromRoomState:summary.room.state];
}
refreshRiotRoomDisplayName = YES;
break;
}
case MXEventTypeRoomMember:
{
if (!riotRoomDisplayName.length)
{
riotRoomDisplayName = [self riotRoomDisplayNameFromRoomState:summary.room.state];
}
refreshRiotRoomDisplayName = YES;
// Do not break here to check avatar url too.
}
case MXEventTypeRoomAvatar:
{
if (!riotRoomAvatarURL.length)
{
riotRoomAvatarURL = [self riotRoomAvatarURLFromRoomState:summary.room.state];
}
refreshRiotRoomAvatarURL = YES;
break;
}
default:
break;
}
if (refreshRiotRoomDisplayName && refreshRiotRoomAvatarURL)
{
break;
}
}
if (refreshRiotRoomDisplayName)
{
NSString *riotRoomDisplayName = [self riotRoomDisplayNameFromRoomState:summary.room.state];
if (riotRoomDisplayName.length && ![summary.displayname isEqualToString:riotRoomDisplayName])
{
summary.displayname = riotRoomDisplayName;
ret = YES;
}
}
if (refreshRiotRoomAvatarURL)
{
NSString *riotRoomAvatarURL = [self riotRoomAvatarURLFromRoomState:summary.room.state];
if (riotRoomAvatarURL.length && ![summary.avatar isEqualToString:riotRoomAvatarURL])
{
summary.avatar = riotRoomAvatarURL;
ret = YES;
}
}
return ret;
}

View file

@ -62,11 +62,6 @@ extern UIStatusBarStyle kRiotDesignStatusBarStyle;
extern UIBarStyle kRiotDesignSearchBarStyle;
extern UIColor *kRiotDesignSearchBarTintColor;
// Flag to enable the display of jitsi conference widget
// TODO: Disable it before release
// TODO: Remove it once Riot web and android are ready
#define USE_JITSI_WIDGET
/**
`RiotDesignValues` class manages the Riot design parameters
*/

View file

@ -96,6 +96,9 @@
[_sendButton setTitle:NSLocalizedStringFromTable(@"bug_report_send", @"Vector", nil) forState:UIControlStateNormal];
[_sendButton setTitle:NSLocalizedStringFromTable(@"bug_report_send", @"Vector", nil) forState:UIControlStateHighlighted];
// Do not send empty report
_sendButton.enabled = NO;;
_sendingContainer.hidden = YES;
self.sendLogs = YES;

View file

@ -23,6 +23,7 @@
#import "AppDelegate.h"
#import "MXRoom+Riot.h"
#import "MXSession+Riot.h"
@interface MasterTabBarController ()
{
@ -454,26 +455,7 @@
// Considering all the current sessions.
for (MXSession *session in mxSessionArray)
{
// Sum all the rooms with missed notifications.
for (MXRoomSummary *roomSummary in session.roomsSummaries)
{
NSUInteger notificationCount = roomSummary.notificationCount;
// Ignore the regular notification count if the room is in 'mentions only" mode at the Riot level.
if (roomSummary.room.isMentionsOnly)
{
// Only the highlighted missed messages must be considered here.
notificationCount = roomSummary.highlightCount;
}
if (notificationCount)
{
roomCount ++;
}
}
// Add the invites count
roomCount += [session invitedRooms].count;
roomCount += [session riot_missedDiscussionsCount];
}
return roomCount;

View file

@ -1945,6 +1945,34 @@
selectedComponent = nil;
}
if (level == 0)
{
// Check status of the selected event
if (selectedEvent.sentState == MXEventSentStatePreparing ||
selectedEvent.sentState == MXEventSentStateEncrypting ||
selectedEvent.sentState == MXEventSentStateSending)
{
[currentAlert addAction:[UIAlertAction actionWithTitle:NSLocalizedStringFromTable(@"room_event_action_cancel_send", @"Vector", nil)
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action)
{
if (weakSelf)
{
typeof(self) self = weakSelf;
self->currentAlert = nil;
// Cancel and remove the outgoing message
[self.roomDataSource.room cancelSendingOperation:selectedEvent.eventId];
[self.roomDataSource removeEventWithEventId:selectedEvent.eventId];
[self cancelEventSelection];
}
}]];
}
}
if (level == 0)
{
[currentAlert addAction:[UIAlertAction actionWithTitle:NSLocalizedStringFromTable(@"room_event_action_copy", @"Vector", nil)
@ -2087,18 +2115,17 @@
// Check status of the selected event
if (selectedEvent.sentState == MXEventSentStatePreparing ||
selectedEvent.sentState == MXEventSentStateEncrypting ||
selectedEvent.sentState == MXEventSentStateUploading)
selectedEvent.sentState == MXEventSentStateUploading ||
selectedEvent.sentState == MXEventSentStateSending)
{
// Upload id is stored in attachment url (nasty trick)
NSString *uploadId = roomBubbleTableViewCell.bubbleData.attachment.actualURL;
if ([MXMediaManager existingUploaderWithId:uploadId])
{
[currentAlert addAction:[UIAlertAction actionWithTitle:NSLocalizedStringFromTable(@"room_event_action_cancel_upload", @"Vector", nil)
[currentAlert addAction:[UIAlertAction actionWithTitle:NSLocalizedStringFromTable(@"room_event_action_cancel_send", @"Vector", nil)
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
// TODO cancel the attachment encryption if it is in progress.
// Get again the loader
MXMediaLoader *loader = [MXMediaManager existingUploaderWithId:uploadId];
if (loader)
@ -2117,6 +2144,9 @@
// Remove the outgoing message and its related cached file.
[[NSFileManager defaultManager] removeItemAtPath:roomBubbleTableViewCell.bubbleData.attachment.cacheFilePath error:nil];
[[NSFileManager defaultManager] removeItemAtPath:roomBubbleTableViewCell.bubbleData.attachment.cacheThumbnailPath error:nil];
// Cancel and remove the outgoing message
[self.roomDataSource.room cancelSendingOperation:selectedEvent.eventId];
[self.roomDataSource removeEventWithEventId:selectedEvent.eventId];
[self cancelEventSelection];
@ -2738,7 +2768,6 @@
{
__weak __typeof(self) weakSelf = self;
#ifdef USE_JITSI_WIDGET
// If there is already a jitsi widget, join it
Widget *jitsiWidget = [customizedRoomDataSource jitsiWidget];
if (jitsiWidget)
@ -2775,11 +2804,8 @@
}
}];
}
else
#endif
// Classic conference call is not supported in encrypted rooms
if (self.roomDataSource.room.state.isEncrypted && self.roomDataSource.room.state.joinedMembers.count > 2)
else if (self.roomDataSource.room.state.isEncrypted && self.roomDataSource.room.state.joinedMembers.count > 2)
{
[currentAlert dismissViewControllerAnimated:NO completion:nil];
@ -3540,7 +3566,6 @@
} onClosePressed:nil];
}
}
#ifdef USE_JITSI_WIDGET
else if (jitsiWidget)
{
// The room has an active jitsi widget
@ -3610,7 +3635,6 @@
}];
}
}
#endif
else if ([self checkUnsentMessages] == NO)
{
// Show "scroll to bottom" icon when the most recent message is not visible,

View file

@ -17,13 +17,14 @@
#import "SettingsViewController.h"
#import "AppDelegate.h"
#import "AvatarGenerator.h"
#import <Photos/Photos.h>
#import <MatrixSDK/MXCallKitAdapter.h>
#import <MediaPlayer/MediaPlayer.h>
#import <MobileCoreServices/MobileCoreServices.h>
#import <OLMKit/OLMKit.h>
#import <Photos/Photos.h>
#import "AppDelegate.h"
#import "AvatarGenerator.h"
#import "MXKEncryptionKeysExportView.h"
#import "BugReportViewController.h"
@ -32,17 +33,14 @@
#import "CountryPickerViewController.h"
#import "LanguagePickerViewController.h"
#import "TableViewCellWithPhoneNumberTextField.h"
#import "NBPhoneNumberUtil.h"
#import "AvatarGenerator.h"
#import "OLMKit/OLMKit.h"
#import "RageShakeManager.h"
#import "RiotDesignValues.h"
#import "TableViewCellWithPhoneNumberTextField.h"
#import "GBDeviceInfo_iOS.h"
NSString* const kSettingsViewControllerPhoneBookCountryCellId = @"kSettingsViewControllerPhoneBookCountryCellId";
enum
@ -50,6 +48,7 @@ enum
SETTINGS_SECTION_SIGN_OUT_INDEX = 0,
SETTINGS_SECTION_USER_SETTINGS_INDEX,
SETTINGS_SECTION_NOTIFICATIONS_SETTINGS_INDEX,
SETTINGS_SECTION_CALLS_INDEX,
SETTINGS_SECTION_USER_INTERFACE_INDEX,
SETTINGS_SECTION_IGNORED_USERS_INDEX,
SETTINGS_SECTION_CONTACTS_INDEX,
@ -64,6 +63,7 @@ enum
enum
{
NOTIFICATION_SETTINGS_ENABLE_PUSH_INDEX = 0,
NOTIFICATION_SETTINGS_SHOW_DECODED_CONTENT,
NOTIFICATION_SETTINGS_GLOBAL_SETTINGS_INDEX,
NOTIFICATION_SETTINGS_PIN_MISSED_NOTIFICATIONS_INDEX,
NOTIFICATION_SETTINGS_PIN_UNREAD_INDEX,
@ -76,6 +76,13 @@ enum
NOTIFICATION_SETTINGS_COUNT
};
enum
{
CALLS_ENABLE_CALLKIT_INDEX = 0,
CALLS_DESCRIPTION_INDEX,
CALLS_COUNT
};
enum
{
USER_INTERFACE_LANGUAGE_INDEX = 0,
@ -92,6 +99,7 @@ enum
OTHER_PRIVACY_INDEX,
OTHER_THIRD_PARTY_INDEX,
OTHER_CRASH_REPORT_INDEX,
OTHER_ENABLE_RAGESHAKE_INDEX,
OTHER_MARK_ALL_AS_READ_INDEX,
OTHER_CLEAR_CACHE_INDEX,
OTHER_REPORT_BUG_INDEX,
@ -101,9 +109,7 @@ enum
enum
{
LABS_MATRIX_APPS_INDEX = 0,
#ifdef USE_JITSI_WIDGET
LABS_USE_JITSI_WIDGET_INDEX,
#endif
LABS_CRYPTO_INDEX,
LABS_COUNT
};
@ -128,7 +134,7 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)();
// listener
id removedAccountObserver;
id accountUserInfoObserver;
id apnsInfoUpdateObserver;
id pushInfoUpdateObserver;
id notificationCenterWillUpdateObserver;
id notificationCenterDidUpdateObserver;
@ -274,8 +280,8 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)();
}];
// Add observer to apns
apnsInfoUpdateObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXKAccountAPNSActivityDidChangeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
// Add observer to push settings
pushInfoUpdateObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXKAccountPushKitActivityDidChangeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
[self stopActivityIndicator];
@ -524,10 +530,10 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)();
accountUserInfoObserver = nil;
}
if (apnsInfoUpdateObserver)
if (pushInfoUpdateObserver)
{
[[NSNotificationCenter defaultCenter] removeObserver:apnsInfoUpdateObserver];
apnsInfoUpdateObserver = nil;
[[NSNotificationCenter defaultCenter] removeObserver:pushInfoUpdateObserver];
pushInfoUpdateObserver = nil;
}
[[NSNotificationCenter defaultCenter] removeObserver:self];
@ -1176,6 +1182,13 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)();
{
count = NOTIFICATION_SETTINGS_COUNT;
}
else if (section == SETTINGS_SECTION_CALLS_INDEX)
{
if ([MXCallKitAdapter callKitAvailable])
{
count = CALLS_COUNT;
}
}
else if (section == SETTINGS_SECTION_USER_INTERFACE_INDEX)
{
count = USER_INTERFACE_COUNT;
@ -1617,13 +1630,25 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)();
MXKTableViewCellWithLabelAndSwitch* labelAndSwitchCell = [self getLabelAndSwitchCell:tableView forIndexPath:indexPath];
labelAndSwitchCell.mxkLabel.text = NSLocalizedStringFromTable(@"settings_enable_push_notif", @"Vector", nil);
labelAndSwitchCell.mxkSwitch.on = account.pushNotificationServiceIsActive;
labelAndSwitchCell.mxkSwitch.on = account.isPushKitNotificationActive;
labelAndSwitchCell.mxkSwitch.enabled = YES;
[labelAndSwitchCell.mxkSwitch removeTarget:self action:nil forControlEvents:UIControlEventTouchUpInside];
[labelAndSwitchCell.mxkSwitch addTarget:self action:@selector(togglePushNotifications:) forControlEvents:UIControlEventTouchUpInside];
cell = labelAndSwitchCell;
}
else if (row == NOTIFICATION_SETTINGS_SHOW_DECODED_CONTENT)
{
MXKTableViewCellWithLabelAndSwitch* labelAndSwitchCell = [self getLabelAndSwitchCell:tableView forIndexPath:indexPath];
labelAndSwitchCell.mxkLabel.text = NSLocalizedStringFromTable(@"settings_show_decrypted_content", @"Vector", nil);
labelAndSwitchCell.mxkSwitch.on = account.showDecryptedContentInNotifications;
labelAndSwitchCell.mxkSwitch.enabled = account.isPushKitNotificationActive;
[labelAndSwitchCell.mxkSwitch removeTarget:self action:nil forControlEvents:UIControlEventTouchUpInside];
[labelAndSwitchCell.mxkSwitch addTarget:self action:@selector(toggleShowDecodedContent:) forControlEvents:UIControlEventTouchUpInside];
cell = labelAndSwitchCell;
}
else if (row == NOTIFICATION_SETTINGS_GLOBAL_SETTINGS_INDEX)
{
MXKTableViewCell *globalInfoCell = [self getDefaultTableViewCell:tableView];
@ -1662,6 +1687,29 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)();
cell = labelAndSwitchCell;
}
}
else if (section == SETTINGS_SECTION_CALLS_INDEX)
{
if (row == CALLS_ENABLE_CALLKIT_INDEX)
{
MXKTableViewCellWithLabelAndSwitch* labelAndSwitchCell = [self getLabelAndSwitchCell:tableView forIndexPath:indexPath];
labelAndSwitchCell.mxkLabel.text = NSLocalizedStringFromTable(@"settings_enable_callkit", @"Vector", nil);
labelAndSwitchCell.mxkSwitch.on = [MXKAppSettings standardAppSettings].isCallKitEnabled;
labelAndSwitchCell.mxkSwitch.enabled = YES;
[labelAndSwitchCell.mxkSwitch removeTarget:self action:nil forControlEvents:UIControlEventTouchUpInside];
[labelAndSwitchCell.mxkSwitch addTarget:self action:@selector(toggleCallKit:) forControlEvents:UIControlEventTouchUpInside];
cell = labelAndSwitchCell;
}
else if (row == CALLS_DESCRIPTION_INDEX)
{
MXKTableViewCell *globalInfoCell = [self getDefaultTableViewCell:tableView];
globalInfoCell.textLabel.text = NSLocalizedStringFromTable(@"settings_callkit_info", @"Vector", nil);
globalInfoCell.textLabel.numberOfLines = 0;
globalInfoCell.selectionStyle = UITableViewCellSelectionStyleNone;
cell = globalInfoCell;
}
}
else if (section == SETTINGS_SECTION_USER_INTERFACE_INDEX)
{
if (row == USER_INTERFACE_LANGUAGE_INDEX)
@ -1867,6 +1915,18 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)();
cell = sendCrashReportCell;
}
else if (row == OTHER_ENABLE_RAGESHAKE_INDEX)
{
MXKTableViewCellWithLabelAndSwitch* enableRageShakeCell = [self getLabelAndSwitchCell:tableView forIndexPath:indexPath];
enableRageShakeCell.mxkLabel.text = NSLocalizedStringFromTable(@"settings_enable_rageshake", @"Vector", nil);
enableRageShakeCell.mxkSwitch.on = [[NSUserDefaults standardUserDefaults] boolForKey:@"enableRageShake"];
enableRageShakeCell.mxkSwitch.enabled = YES;
[enableRageShakeCell.mxkSwitch removeTarget:self action:nil forControlEvents:UIControlEventTouchUpInside];
[enableRageShakeCell.mxkSwitch addTarget:self action:@selector(toggleEnableRageShake:) forControlEvents:UIControlEventTouchUpInside];
cell = enableRageShakeCell;
}
else if (row == OTHER_MARK_ALL_AS_READ_INDEX)
{
MXKTableViewCellWithButton *markAllBtnCell = [tableView dequeueReusableCellWithIdentifier:[MXKTableViewCellWithButton defaultReuseIdentifier]];
@ -1957,7 +2017,6 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)();
cell = labelAndSwitchCell;
}
#ifdef USE_JITSI_WIDGET
else if (row == LABS_USE_JITSI_WIDGET_INDEX)
{
MXKTableViewCellWithLabelAndSwitch* labelAndSwitchCell = [self getLabelAndSwitchCell:tableView forIndexPath:indexPath];
@ -1970,9 +2029,7 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)();
cell = labelAndSwitchCell;
}
else
#endif
if (row == LABS_CRYPTO_INDEX)
else if (row == LABS_CRYPTO_INDEX)
{
MXSession* session = [[AppDelegate theDelegate].mxSessions objectAtIndex:0];
@ -2077,6 +2134,13 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)();
{
return NSLocalizedStringFromTable(@"settings_notifications_settings", @"Vector", nil);
}
else if (section == SETTINGS_SECTION_CALLS_INDEX)
{
if ([MXCallKitAdapter callKitAvailable])
{
return NSLocalizedStringFromTable(@"settings_calls_settings", @"Vector", nil);
}
}
else if (section == SETTINGS_SECTION_USER_INTERFACE_INDEX)
{
return NSLocalizedStringFromTable(@"settings_user_interface", @"Vector", nil);
@ -2201,6 +2265,13 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)();
}
}
}
else if (section == SETTINGS_SECTION_CALLS_INDEX)
{
if (![MXCallKitAdapter callKitAvailable])
{
return SECTION_TITLE_PADDING_WHEN_HIDDEN;
}
}
return 24;
}
@ -2219,6 +2290,13 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)();
}
}
}
else if (section == SETTINGS_SECTION_CALLS_INDEX)
{
if (![MXCallKitAdapter callKitAvailable])
{
return SECTION_TITLE_PADDING_WHEN_HIDDEN;
}
}
return 24;
}
@ -2648,9 +2726,9 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)();
MXKAccountManager *accountManager = [MXKAccountManager sharedManager];
MXKAccount* account = accountManager.activeAccounts.firstObject;
if (accountManager.apnsDeviceToken)
if (accountManager.pushDeviceToken)
{
[account setEnablePushNotifications:!account.pushNotificationServiceIsActive];
[account setEnablePushKitNotifications:!account.isPushKitNotificationActive];
}
else
{
@ -2663,13 +2741,25 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)();
}
else
{
[account setEnablePushNotifications:YES];
[account setEnablePushKitNotifications:YES];
}
}];
}
}
}
- (void)toggleCallKit:(id)sender
{
UISwitch *switchButton = (UISwitch*)sender;
[MXKAppSettings standardAppSettings].enableCallKit = switchButton.isOn;
}
- (void)toggleShowDecodedContent:(id)sender
{
MXKAccount* account = [MXKAccountManager sharedManager].activeAccounts.firstObject;
account.showDecryptedContentInNotifications = !account.showDecryptedContentInNotifications;
}
- (void)toggleLocalContactsSync:(id)sender
{
UISwitch *switchButton = (UISwitch*)sender;
@ -2715,6 +2805,19 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)();
}
}
- (void)toggleEnableRageShake:(id)sender
{
if (sender && [sender isKindOfClass:UISwitch.class])
{
UISwitch *switchButton = (UISwitch*)sender;
[[NSUserDefaults standardUserDefaults] setBool:switchButton.isOn forKey:@"enableRageShake"];
[[NSUserDefaults standardUserDefaults] synchronize];
[self.tableView reloadData];
}
}
- (void)toggleLabsMatrixApps:(id)sender
{
if (sender && [sender isKindOfClass:UISwitch.class])

View file

@ -17,7 +17,7 @@
<key>CFBundlePackageType</key>
<string>XPC!</string>
<key>CFBundleShortVersionString</key>
<string>0.5.3</string>
<string>0.5.6</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>NSExtension</key>
@ -29,13 +29,13 @@
<key>NSExtensionActivationRule</key>
<dict>
<key>NSExtensionActivationSupportsMovieWithMaxCount</key>
<integer>0</integer>
<integer>1</integer>
<key>NSExtensionActivationSupportsImageWithMaxCount</key>
<integer>0</integer>
<integer>5</integer>
<key>NSExtensionActivationSupportsWebURLWithMaxCount</key>
<integer>0</integer>
<integer>1</integer>
<key>NSExtensionActivationSupportsText</key>
<false/>
<true/>
</dict>
</dict>
<key>NSExtensionPointIdentifier</key>

41
SiriIntents/Info.plist Normal file
View file

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>SiriIntents</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>XPC!</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>NSExtension</key>
<dict>
<key>NSExtensionAttributes</key>
<dict>
<key>IntentsRestrictedWhileLocked</key>
<array/>
<key>IntentsSupported</key>
<array>
<string>INStartAudioCallIntent</string>
<string>INStartVideoCallIntent</string>
</array>
</dict>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.intents-service</string>
<key>NSExtensionPrincipalClass</key>
<string>IntentHandler</string>
</dict>
</dict>
</plist>

View file

@ -0,0 +1,21 @@
/*
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 <Intents/Intents.h>
@interface IntentHandler : INExtension
@end

302
SiriIntents/IntentHandler.m Normal file
View file

@ -0,0 +1,302 @@
/*
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 "IntentHandler.h"
#import "MXKAccount.h"
#import "MXKAccountManager.h"
#import "MXFileStore.h"
#import "MXSession.h"
@interface IntentHandler () <INStartAudioCallIntentHandling, INStartVideoCallIntentHandling>
@end
@implementation IntentHandler
- (instancetype)init
{
self = [super init];
if (self)
{
[MXSDKOptions sharedInstance].applicationGroupIdentifier = @"group.im.vector";
}
return self;
}
- (id)handlerForIntent:(INIntent *)intent
{
return self;
}
#pragma mark - INStartAudioCallIntentHandling
- (void)resolveContactsForStartAudioCall:(INStartAudioCallIntent *)intent withCompletion:(void (^)(NSArray<INPersonResolutionResult *> * _Nonnull))completion
{
[self resolveContacts:intent.contacts withCompletion:completion];
}
- (void)confirmStartAudioCall:(INStartAudioCallIntent *)intent completion:(void (^)(INStartAudioCallIntentResponse * _Nonnull))completion
{
INStartAudioCallIntentResponse *response = nil;
MXKAccount *account = [MXKAccountManager sharedManager].activeAccounts.firstObject;
if (account)
{
#if defined MX_CALL_STACK_OPENWEBRTC || defined MX_CALL_STACK_ENDPOINT || defined MX_CALL_STACK_JINGLE
NSUserActivity *userActivity = [[NSUserActivity alloc] initWithActivityType:NSStringFromClass(INStartAudioCallIntent.class)];
response = [[INStartAudioCallIntentResponse alloc] initWithCode:INStartAudioCallIntentResponseCodeReady userActivity:userActivity];
#else
response = [[INStartAudioCallIntentResponse alloc] initWithCode:INStartAudioCallIntentResponseCodeFailureCallingServiceNotAvailable userActivity:nil];
#endif
}
else
{
// User hasn't logged in
response = [[INStartAudioCallIntentResponse alloc] initWithCode:INStartAudioCallIntentResponseCodeFailureAppConfigurationRequired userActivity:nil];
}
completion(response);
}
- (void)handleStartAudioCall:(INStartAudioCallIntent *)intent completion:(void (^)(INStartAudioCallIntentResponse * _Nonnull))completion
{
INStartAudioCallIntentResponse *response = nil;
INPerson *person = intent.contacts.firstObject;
if (person && person.customIdentifier)
{
NSUserActivity *userActivity = [[NSUserActivity alloc] initWithActivityType:NSStringFromClass(INStartAudioCallIntent.class)];
userActivity.userInfo = @{ @"roomID" : person.customIdentifier };
response = [[INStartAudioCallIntentResponse alloc] initWithCode:INStartAudioCallIntentResponseCodeContinueInApp
userActivity:userActivity];
}
else
{
response = [[INStartAudioCallIntentResponse alloc] initWithCode:INStartAudioCallIntentResponseCodeFailure userActivity:nil];
}
completion(response);
}
#pragma mark - INStartVideoCallIntentHandling
- (void)resolveContactsForStartVideoCall:(INStartVideoCallIntent *)intent withCompletion:(void (^)(NSArray<INPersonResolutionResult *> * _Nonnull))completion
{
[self resolveContacts:intent.contacts withCompletion:completion];
}
- (void)confirmStartVideoCall:(INStartVideoCallIntent *)intent completion:(void (^)(INStartVideoCallIntentResponse * _Nonnull))completion
{
INStartVideoCallIntentResponse *response = nil;
MXKAccount *account = [MXKAccountManager sharedManager].activeAccounts.firstObject;
if (account)
{
#if defined MX_CALL_STACK_OPENWEBRTC || defined MX_CALL_STACK_ENDPOINT || defined MX_CALL_STACK_JINGLE
NSUserActivity *userActivity = [[NSUserActivity alloc] initWithActivityType:NSStringFromClass(INStartVideoCallIntent.class)];
response = [[INStartVideoCallIntentResponse alloc] initWithCode:INStartVideoCallIntentResponseCodeReady userActivity:userActivity];
#else
response = [[INStartVideoCallIntentResponse alloc] initWithCode:INStartVideoCallIntentResponseCodeFailureCallingServiceNotAvailable userActivity:nil];
#endif
}
else
{
// User hasn't logged in
response = [[INStartVideoCallIntentResponse alloc] initWithCode:INStartVideoCallIntentResponseCodeFailureRequiringAppLaunch userActivity:nil];
}
completion(response);
}
- (void)handleStartVideoCall:(INStartVideoCallIntent *)intent completion:(void (^)(INStartVideoCallIntentResponse * _Nonnull))completion
{
INStartVideoCallIntentResponse *response = nil;
INPerson *person = intent.contacts.firstObject;
if (person && person.customIdentifier)
{
NSUserActivity *userActivity = [[NSUserActivity alloc] initWithActivityType:NSStringFromClass(INStartVideoCallIntent.class)];
userActivity.userInfo = @{ @"roomID" : person.customIdentifier };
response = [[INStartVideoCallIntentResponse alloc] initWithCode:INStartVideoCallIntentResponseCodeContinueInApp
userActivity:userActivity];
}
else
{
response = [[INStartVideoCallIntentResponse alloc] initWithCode:INStartVideoCallIntentResponseCodeFailure userActivity:nil];
}
completion(response);
}
#pragma mark - Private
- (void)resolveContacts:(nullable NSArray<INPerson *> *)contacts withCompletion:(void (^)(NSArray<INPersonResolutionResult *> * _Nonnull))completion
{
if (contacts.count == 0)
{
completion(@[[INPersonResolutionResult needsValue]]);
return;
}
else
{
// We don't iterate over array of contacts from passed intent
// since it's hard to imagine scenario with several callee
// so we just extract the first one
INPerson *callee = contacts.firstObject;
// If this method is called after selection of the appropriate user, it will hold userId of an user to whom we must call
NSString *selectedUserId;
// Check if the user has selected right room among several direct rooms from previous resolution process run
if (callee.customIdentifier.length)
{
// If callee will have the same name as one of the contact in the system contacts app
// Siri will pass us this contact in the intent.contacts array and we must provide the same count of
// resolution results as elements count in the intent.contact.
// So we just pass the same result at all iterations
NSMutableArray *resolutionResults = [NSMutableArray array];
for (NSInteger i = 0; i < contacts.count; ++i)
[resolutionResults addObject:[INPersonResolutionResult successWithResolvedPerson:callee]];
completion(resolutionResults);
return;
}
else
{
// This resolution process run after selecting appropriate user among suggested user list
selectedUserId = callee.personHandle.value;
}
MXKAccount *account = [MXKAccountManager sharedManager].activeAccounts.firstObject;
if (account)
{
MXFileStore *fileStore = [[MXFileStore alloc] initWithCredentials:account.mxCredentials];
[fileStore asyncRoomsSummaries:^(NSArray<MXRoomSummary *> * _Nonnull roomsSummaries) {
// Contains userIds of all users with whom the current user has direct chats
// Use set to avoid duplicates
NSMutableSet<NSString *> *directUserIds = [NSMutableSet set];
// Contains room summaries for all direct rooms connected with particular userId
NSMutableDictionary<NSString *, NSMutableArray<MXRoomSummary *> *> *roomSummaries = [NSMutableDictionary dictionary];
for (MXRoomSummary *summary in roomsSummaries)
{
// TODO: We also need to check if joined room members count equals 2
// It is pointlessly to save rooms with 1 joined member or room with more than 2 joined members
if (summary.isDirect)
{
NSString *diretUserId = summary.directUserId;
// Collect room summaries only for specified user
if (selectedUserId && ![diretUserId isEqualToString:selectedUserId])
continue;
// Save userId
[directUserIds addObject:diretUserId];
// Save associated with diretUserId room summary
NSMutableArray<MXRoomSummary *> *userRoomSummaries = roomSummaries[diretUserId];
if (userRoomSummaries)
[userRoomSummaries addObject:summary];
else
roomSummaries[diretUserId] = [NSMutableArray arrayWithObject:summary];
}
}
[fileStore asyncUsersWithUserIds:directUserIds.allObjects success:^(NSArray<MXUser *> * _Nonnull users) {
// Find users whose display name contains string presented us by Siri
NSMutableArray<MXUser *> *matchingUsers = [NSMutableArray array];
for (MXUser *user in users)
{
if (!user.displayname)
continue;
if (!NSEqualRanges([callee.displayName rangeOfString:user.displayname options:NSCaseInsensitiveSearch], (NSRange){NSNotFound,0}))
{
[matchingUsers addObject:user];
}
}
NSMutableArray<INPerson *> *persons = [NSMutableArray array];
if (matchingUsers.count == 1)
{
MXUser *user = matchingUsers.firstObject;
// Provide to the user a list of direct rooms to choose from
NSArray<MXRoomSummary *> *summaries = roomSummaries[user.userId];
for (MXRoomSummary *summary in summaries)
{
INPersonHandle *personHandle = [[INPersonHandle alloc] initWithValue:user.userId type:INPersonHandleTypeUnknown];
// For rooms we try to use room display name
NSString *displayName = summary.displayname ? summary.displayname : user.displayname;
INPerson *person = [[INPerson alloc] initWithPersonHandle:personHandle
nameComponents:nil
displayName:displayName
image:nil
contactIdentifier:nil
customIdentifier:summary.roomId];
[persons addObject:person];
}
}
else if (matchingUsers.count > 1)
{
// Provide to the user a list of users to choose from
// This is the case when there are several users with the same name
for (MXUser *user in matchingUsers)
{
INPersonHandle *personHandle = [[INPersonHandle alloc] initWithValue:user.userId type:INPersonHandleTypeUnknown];
INPerson *person = [[INPerson alloc] initWithPersonHandle:personHandle
nameComponents:nil
displayName:user.displayname
image:nil
contactIdentifier:nil
customIdentifier:nil];
[persons addObject:person];
}
}
if (persons.count == 0)
{
completion(@[[INPersonResolutionResult unsupported]]);
}
else if (persons.count == 1)
{
completion(@[[INPersonResolutionResult successWithResolvedPerson:persons.firstObject]]);
}
else
{
completion(@[[INPersonResolutionResult disambiguationWithPeopleToDisambiguate:persons]]);
}
} failure:nil];
} failure:nil];
}
else
{
completion(@[[INPersonResolutionResult notRequired]]);
}
}
}
@end

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.application-groups</key>
<array>
<string>group.im.vector</string>
</array>
</dict>
</plist>