Merge branch 'master' into callkit

# Conflicts:
#	Riot.xcodeproj/project.pbxproj
#	Riot/AppDelegate.m
#	Riot/ViewController/SettingsViewController.m
This commit is contained in:
Giom Foret 2017-10-04 13:04:21 +02:00
commit 7801cabe32
74 changed files with 2169 additions and 889 deletions

View file

@ -26,4 +26,7 @@ Denis Morozov <dmorozkn at gmail.com>
Aram Sargsyan <aram.sargsyan.1997 at gmail.com>
* PR #1341: Read receipts details
Vivian Lim <vivvnlim at gmail.com>
* PR #1513 Return key on hardware keyboards now sends messages

View file

@ -1,3 +1,48 @@
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)
===============================================

14
Podfile
View file

@ -7,7 +7,7 @@ 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'
@ -21,7 +21,7 @@ pod 'MatrixKit', '0.6.2'
#pod 'MatrixKit', :path => '../matrix-ios-kit/MatrixKit.podspec'
#pod 'MatrixSDK', :path => '../matrix-ios-sdk/MatrixSDK.podspec'
pod 'GBDeviceInfo', '~> 4.3.0'
pod 'GBDeviceInfo', '~> 4.4.0'
pod 'GoogleAnalytics'
@ -31,7 +31,7 @@ pod 'WebRTC', '58.17.16937'
# OLMKit for crypto
pod 'OLMKit'
#pod 'OLMKit', :path => '../olm/OLMKit.podspec'
pod 'Realm', '~> 2.8.1'
pod 'Realm', '~> 2.10.2'
# Remove warnings from "bad" pods
pod 'OLMKit', :inhibit_warnings => true
@ -49,10 +49,10 @@ pod 'WebRTC', '58.17.16937'
# OLMKit for crypto
pod 'OLMKit'
#pod 'OLMKit', :path => '../olm/OLMKit.podspec'
pod 'Realm', '~> 2.8.1'
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'
@ -81,10 +81,10 @@ pod 'WebRTC', '58.17.16937'
# OLMKit for crypto
pod 'OLMKit'
#pod 'OLMKit', :path => '../olm/OLMKit.podspec'
pod 'Realm', '~> 2.8.1'
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'

View file

@ -15,18 +15,18 @@ PODS:
- AFNetworking/UIKit (3.1.0):
- AFNetworking/NSURLSession
- cmark (0.24.1)
- DTCoreText (1.6.20):
- DTCoreText/Core (= 1.6.20)
- DTCoreText (1.6.21):
- DTCoreText/Core (= 1.6.21)
- DTFoundation/Core (~> 1.7.5)
- DTFoundation/DTAnimatedGIF (~> 1.7.5)
- DTFoundation/DTHTMLParser (~> 1.7.5)
- DTFoundation/UIKit (~> 1.7.5)
- DTCoreText/Core (1.6.20):
- DTCoreText/Core (1.6.21):
- DTFoundation/Core (~> 1.7.5)
- DTFoundation/DTAnimatedGIF (~> 1.7.5)
- DTFoundation/DTHTMLParser (~> 1.7.5)
- DTFoundation/UIKit (~> 1.7.5)
- DTCoreText/Extension (1.6.20):
- DTCoreText/Extension (1.6.21):
- DTFoundation/Core (~> 1.7.5)
- DTFoundation/DTAnimatedGIF (~> 1.7.5)
- DTFoundation/DTHTMLParser (~> 1.7.5)
@ -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,38 +72,38 @@ 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:
AFNetworking: 5e0e199f73d8626b11e79750991f5d173d1f8b67
cmark: ec0275215b504780287b6fca360224e384368af8
DTCoreText: 51904f2374af443e0d270d6fdc76035ab6f9ef8a
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

View file

@ -10,13 +10,15 @@
05D592A32FF1D1877B89F73C /* libPods-Riot.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FD9D0BDE9232898950554DD5 /* libPods-Riot.a */; };
2435179C1F375B9400D0683E /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 2466B7551F2F80B800AE27B0 /* Info.plist */; };
2435179F1F375C0F00D0683E /* Vector.strings in Resources */ = {isa = PBXBuildFile; fileRef = 327382C01F276AED00356143 /* Vector.strings */; };
2439DD621F6BBE760090F42D /* RecentRoomTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 2439DD611F6BBE760090F42D /* RecentRoomTableViewCell.m */; };
2439DD641F6BBEA50090F42D /* RecentRoomTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2439DD631F6BBEA50090F42D /* RecentRoomTableViewCell.xib */; };
245FC3ED1F3D079A00603C6A /* ShareExtensionManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 245FC3EB1F3CAF9800603C6A /* ShareExtensionManager.m */; };
245FC3EF1F3DD30800603C6A /* RecentCellData.m in Sources */ = {isa = PBXBuildFile; fileRef = F083BC071E7009EC00A9B29C /* RecentCellData.m */; };
2466B73E1F2DFAC100AE27B0 /* animatedLogo-4.png in Resources */ = {isa = PBXBuildFile; fileRef = F083BB201E7009EC00A9B29C /* animatedLogo-4.png */; };
24B5103E1EFA7083004C6AD2 /* ReadReceiptsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 24B5103D1EFA7083004C6AD2 /* ReadReceiptsViewController.m */; };
24B510401EFA88CC004C6AD2 /* ReadReceiptsViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 24B5103F1EFA88CC004C6AD2 /* ReadReceiptsViewController.xib */; };
24CBEC591F0EAD310093EABB /* RiotShareExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 24CBEC4E1F0EAD310093EABB /* RiotShareExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
24D6B3581F3C90D300FC7A71 /* ShareRecentsDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 24D6B3571F3C90D300FC7A71 /* ShareRecentsDataSource.m */; };
24D6B3581F3C90D300FC7A71 /* ShareDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 24D6B3571F3C90D300FC7A71 /* ShareDataSource.m */; };
24D6B3591F3CA02900FC7A71 /* SharePresentingViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 24D6B34B1F3C8F8A00FC7A71 /* SharePresentingViewController.m */; };
24D6B35A1F3CA02C00FC7A71 /* ShareViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 24D6B34D1F3C8F8A00FC7A71 /* ShareViewController.m */; };
24D6B35B1F3CA03300FC7A71 /* ShareViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 24D6B34E1F3C8F8A00FC7A71 /* ShareViewController.xib */; };
@ -73,6 +75,7 @@
32AE61F21F0D2183007255F4 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 32AE61EC1F0D2183007255F4 /* InfoPlist.strings */; };
32AE61F31F0D2183007255F4 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 32AE61EE1F0D2183007255F4 /* Localizable.strings */; };
32AE61F41F0D2183007255F4 /* Vector.strings in Resources */ = {isa = PBXBuildFile; fileRef = 32AE61F01F0D2183007255F4 /* Vector.strings */; };
32C2356F1F7B871800E38FC5 /* WidgetPickerViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 32C2356E1F7B871800E38FC5 /* WidgetPickerViewController.m */; };
32D392181EB9B7AB009A2BAF /* DirectoryServerDetailTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D392161EB9B7AB009A2BAF /* DirectoryServerDetailTableViewCell.m */; };
32D392191EB9B7AB009A2BAF /* DirectoryServerDetailTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 32D392171EB9B7AB009A2BAF /* DirectoryServerDetailTableViewCell.xib */; };
32E84FA11F6BD32700CA0B89 /* apps-icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 32E84F9E1F6BD32700CA0B89 /* apps-icon.png */; };
@ -82,6 +85,7 @@
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 */; };
@ -91,6 +95,11 @@
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 */; };
@ -495,6 +504,10 @@
F0A4A1671EF7CB66003630DB /* members_list_icon.png in Resources */ = {isa = PBXBuildFile; fileRef = F0A4A1641EF7CB66003630DB /* members_list_icon.png */; };
F0A4A1681EF7CB66003630DB /* members_list_icon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = F0A4A1651EF7CB66003630DB /* members_list_icon@2x.png */; };
F0A4A1691EF7CB66003630DB /* members_list_icon@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = F0A4A1661EF7CB66003630DB /* members_list_icon@3x.png */; };
F0A8955F1F7D1FEA00BD6C2A /* MXRoomSummary+Riot.m in Sources */ = {isa = PBXBuildFile; fileRef = F0D2ADA01F6AA5FD00A7097D /* MXRoomSummary+Riot.m */; };
F0A895601F7D404B00BD6C2A /* e2e_verified.png in Resources */ = {isa = PBXBuildFile; fileRef = F083BB681E7009EC00A9B29C /* e2e_verified.png */; };
F0A895611F7D404E00BD6C2A /* e2e_verified@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = F083BB691E7009EC00A9B29C /* e2e_verified@2x.png */; };
F0A895621F7D405000BD6C2A /* e2e_verified@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = F083BB6A1E7009EC00A9B29C /* e2e_verified@3x.png */; };
F0B4CBA51F418D0B008E99C5 /* WebViewViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = F0B4CBA41F418D0B008E99C5 /* WebViewViewController.m */; };
F0B4CBA71F41CA44008E99C5 /* DeviceView.xib in Resources */ = {isa = PBXBuildFile; fileRef = F0B4CBA61F41CA44008E99C5 /* DeviceView.xib */; };
F0B4CBAA1F41E71A008E99C5 /* RiotNavigationController.m in Sources */ = {isa = PBXBuildFile; fileRef = F0B4CBA91F41E71A008E99C5 /* RiotNavigationController.m */; };
@ -591,6 +604,9 @@
/* Begin PBXFileReference section */
12AA0005C8B3D8D8162584C5 /* Pods-RiotShareExtension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RiotShareExtension.debug.xcconfig"; path = "Pods/Target Support Files/Pods-RiotShareExtension/Pods-RiotShareExtension.debug.xcconfig"; sourceTree = "<group>"; };
2439DD601F6BBE760090F42D /* RecentRoomTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RecentRoomTableViewCell.h; sourceTree = "<group>"; };
2439DD611F6BBE760090F42D /* RecentRoomTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RecentRoomTableViewCell.m; sourceTree = "<group>"; };
2439DD631F6BBEA50090F42D /* RecentRoomTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = RecentRoomTableViewCell.xib; sourceTree = "<group>"; };
245FC3EA1F3CAF9800603C6A /* ShareExtensionManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ShareExtensionManager.h; sourceTree = "<group>"; };
245FC3EB1F3CAF9800603C6A /* ShareExtensionManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ShareExtensionManager.m; sourceTree = "<group>"; };
2466B7551F2F80B800AE27B0 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = RiotShareExtension/Info.plist; sourceTree = SOURCE_ROOT; };
@ -609,8 +625,8 @@
24D6B34C1F3C8F8A00FC7A71 /* ShareViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ShareViewController.h; sourceTree = "<group>"; };
24D6B34D1F3C8F8A00FC7A71 /* ShareViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ShareViewController.m; sourceTree = "<group>"; };
24D6B34E1F3C8F8A00FC7A71 /* ShareViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ShareViewController.xib; sourceTree = "<group>"; };
24D6B3561F3C90D300FC7A71 /* ShareRecentsDataSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ShareRecentsDataSource.h; sourceTree = "<group>"; };
24D6B3571F3C90D300FC7A71 /* ShareRecentsDataSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ShareRecentsDataSource.m; sourceTree = "<group>"; };
24D6B3561F3C90D300FC7A71 /* ShareDataSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ShareDataSource.h; sourceTree = "<group>"; };
24D6B3571F3C90D300FC7A71 /* ShareDataSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ShareDataSource.m; sourceTree = "<group>"; };
3205ED7B1E976C8A003D65FA /* DirectoryServerPickerViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DirectoryServerPickerViewController.h; sourceTree = "<group>"; };
3205ED7C1E976C8A003D65FA /* DirectoryServerPickerViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DirectoryServerPickerViewController.m; sourceTree = "<group>"; };
3205ED811E97725E003D65FA /* DirectoryServerTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DirectoryServerTableViewCell.h; sourceTree = "<group>"; };
@ -662,6 +678,8 @@
32AE61ED1F0D2183007255F4 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = InfoPlist.strings; sourceTree = "<group>"; };
32AE61EF1F0D2183007255F4 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = Localizable.strings; sourceTree = "<group>"; };
32AE61F11F0D2183007255F4 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = Vector.strings; sourceTree = "<group>"; };
32C2356D1F7B871800E38FC5 /* WidgetPickerViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WidgetPickerViewController.h; sourceTree = "<group>"; };
32C2356E1F7B871800E38FC5 /* WidgetPickerViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = WidgetPickerViewController.m; sourceTree = "<group>"; };
32D392151EB9B7AB009A2BAF /* DirectoryServerDetailTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DirectoryServerDetailTableViewCell.h; sourceTree = "<group>"; };
32D392161EB9B7AB009A2BAF /* DirectoryServerDetailTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DirectoryServerDetailTableViewCell.m; sourceTree = "<group>"; };
32D392171EB9B7AB009A2BAF /* DirectoryServerDetailTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = DirectoryServerDetailTableViewCell.xib; sourceTree = "<group>"; };
@ -678,6 +696,7 @@
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>"; };
839BB91240D350D5607D55BA /* Pods-Riot.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Riot.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Riot/Pods-Riot.debug.xcconfig"; sourceTree = "<group>"; };
92324BE11F4F66D3009DE194 /* IncomingCallView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IncomingCallView.h; sourceTree = "<group>"; };
92324BE21F4F66D3009DE194 /* IncomingCallView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IncomingCallView.m; sourceTree = "<group>"; };
@ -696,6 +715,11 @@
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>"; };
@ -1308,12 +1332,24 @@
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
2439DD5F1F6BBE390090F42D /* Views */ = {
isa = PBXGroup;
children = (
2439DD601F6BBE760090F42D /* RecentRoomTableViewCell.h */,
2439DD611F6BBE760090F42D /* RecentRoomTableViewCell.m */,
2439DD631F6BBEA50090F42D /* RecentRoomTableViewCell.xib */,
);
name = Views;
path = RiotShareExtension/Views;
sourceTree = SOURCE_ROOT;
};
24CBEC4F1F0EAD310093EABB /* RiotShareExtension */ = {
isa = PBXGroup;
children = (
2466B7551F2F80B800AE27B0 /* Info.plist */,
2466B7561F2F80B800AE27B0 /* RiotShareExtension.entitlements */,
24D6B3441F3C8F8A00FC7A71 /* ViewController */,
2439DD5F1F6BBE390090F42D /* Views */,
24D6B3551F3C8FCC00FC7A71 /* Model */,
);
name = RiotShareExtension;
@ -1344,8 +1380,8 @@
children = (
245FC3EA1F3CAF9800603C6A /* ShareExtensionManager.h */,
245FC3EB1F3CAF9800603C6A /* ShareExtensionManager.m */,
24D6B3561F3C90D300FC7A71 /* ShareRecentsDataSource.h */,
24D6B3571F3C90D300FC7A71 /* ShareRecentsDataSource.m */,
24D6B3561F3C90D300FC7A71 /* ShareDataSource.h */,
24D6B3571F3C90D300FC7A71 /* ShareDataSource.m */,
);
name = Model;
path = RiotShareExtension/Model;
@ -1382,6 +1418,8 @@
3233F72E1F31F4BF006ACA81 /* JitsiViewController.h */,
3233F72F1F31F4BF006ACA81 /* JitsiViewController.m */,
3233F7301F31F4BF006ACA81 /* JitsiViewController.xib */,
32C2356D1F7B871800E38FC5 /* WidgetPickerViewController.h */,
32C2356E1F7B871800E38FC5 /* WidgetPickerViewController.m */,
);
path = Widgets;
sourceTree = "<group>";
@ -1506,6 +1544,25 @@
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 */ = {
@ -1559,6 +1616,8 @@
F083BB0E1E7009EC00A9B29C /* Assets */ = {
isa = PBXGroup;
children = (
F04AF2631F83A4C000D20F4D /* eu.lproj */,
F04AF25E1F83A4C000D20F4D /* zh_Hans.lproj */,
32918EA41F473BDB0076CA16 /* ru.lproj */,
327382A71F276AD200356143 /* de.lproj */,
327382BB1F276AED00356143 /* en.lproj */,
@ -2251,6 +2310,7 @@
F083BCD91E7009EC00A9B29C /* RoomInputToolbarView.h */,
F083BCDA1E7009EC00A9B29C /* RoomInputToolbarView.m */,
F083BCDB1E7009EC00A9B29C /* RoomInputToolbarView.xib */,
83711A7B1F6F8E7D008F0D4D /* KeyboardGrowingTextView.m */,
);
path = RoomInputToolbar;
sourceTree = "<group>";
@ -2547,6 +2607,8 @@
de,
fr,
ru,
zh_Hans,
eu,
);
mainGroup = F094A9991B78D8F000B1FBBF;
productRefGroup = F094A9A31B78D8F000B1FBBF /* Products */;
@ -2570,14 +2632,19 @@
24EEE5B51F2607C500B3C705 /* SegmentedViewController.xib in Resources */,
24EEE5A91F25529900B3C705 /* cancel@2x.png in Resources */,
F0B7A8B11F475783006E27D2 /* RoomsListViewController.xib in Resources */,
F0A895621F7D405000BD6C2A /* e2e_verified@3x.png in Resources */,
2435179C1F375B9400D0683E /* Info.plist in Resources */,
24EEE5A81F25529600B3C705 /* cancel@3x.png in Resources */,
2466B73E1F2DFAC100AE27B0 /* animatedLogo-4.png in Resources */,
2435179F1F375C0F00D0683E /* Vector.strings in Resources */,
24EEE5AF1F25F0F500B3C705 /* Images.xcassets in Resources */,
F0A895611F7D404E00BD6C2A /* e2e_verified@2x.png in Resources */,
24EEE5AA1F25529C00B3C705 /* cancel.png in Resources */,
F0A895601F7D404B00BD6C2A /* e2e_verified.png in Resources */,
24D6B35E1F3CA03E00FC7A71 /* FallbackViewController.xib in Resources */,
24EEE5A41F24C06E00B3C705 /* (null) in Resources */,
2439DD641F6BBEA50090F42D /* RecentRoomTableViewCell.xib in Resources */,
24EEE5A41F24C06E00B3C705 /* (null) in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -2657,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 */,
@ -2689,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 */,
@ -2778,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 */,
@ -2791,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 */,
@ -2914,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 */,
@ -3151,7 +3223,7 @@
buildActionMask = 2147483647;
files = (
24EEE5A01F23A08900B3C705 /* RoomTableViewCell.m in Sources */,
24D6B3581F3C90D300FC7A71 /* ShareRecentsDataSource.m in Sources */,
24D6B3581F3C90D300FC7A71 /* ShareDataSource.m in Sources */,
245FC3EF1F3DD30800603C6A /* RecentCellData.m in Sources */,
24D6B35C1F3CA03600FC7A71 /* RoomsListViewController.m in Sources */,
24D6B35A1F3CA02C00FC7A71 /* ShareViewController.m in Sources */,
@ -3160,6 +3232,8 @@
24D6B35D1F3CA03A00FC7A71 /* FallbackViewController.m in Sources */,
24EEE5A11F23A09A00B3C705 /* RiotDesignValues.m in Sources */,
24EEE5A21F23A8B400B3C705 /* MXRoom+Riot.m in Sources */,
F0A8955F1F7D1FEA00BD6C2A /* MXRoomSummary+Riot.m in Sources */,
2439DD621F6BBE760090F42D /* RecentRoomTableViewCell.m in Sources */,
245FC3ED1F3D079A00603C6A /* ShareExtensionManager.m in Sources */,
24EEE5B41F2607C000B3C705 /* SegmentedViewController.m in Sources */,
);
@ -3209,6 +3283,7 @@
32471CDC1F1373A100BDF50A /* RoomMembershipCollapsedWithPaginationTitleBubbleCell.m in Sources */,
F083BE2B1E7009ED00A9B29C /* AuthInputsView.m in Sources */,
321082B21F0E9F40002E0091 /* RoomMembershipCollapsedBubbleCell.m in Sources */,
32C2356F1F7B871800E38FC5 /* WidgetPickerViewController.m in Sources */,
F083BE661E7009ED00A9B29C /* RoomIncomingTextMsgWithPaginationTitleBubbleCell.m in Sources */,
F083BE141E7009ED00A9B29C /* HomeViewController.m in Sources */,
F083BDFB1E7009ED00A9B29C /* RoomSearchDataSource.m in Sources */,
@ -3235,6 +3310,7 @@
3205ED7D1E976C8A003D65FA /* DirectoryServerPickerViewController.m in Sources */,
F083BE7C1E7009ED00A9B29C /* DirectoryRecentTableViewCell.m in Sources */,
F0E05A031E963103004B83FB /* RoomsViewController.m in Sources */,
83711A7C1F6F8E7D008F0D4D /* KeyboardGrowingTextView.m in Sources */,
F083BE801E7009ED00A9B29C /* PublicRoomTableViewCell.m in Sources */,
322806A01F0F64C4008C53D7 /* RoomMembershipExpandedBubbleCell.m in Sources */,
F083BE031E7009ED00A9B29C /* EventFormatter.m in Sources */,
@ -3474,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 = (

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) {
@ -160,6 +152,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

@ -463,9 +463,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.
// 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.
@ -532,6 +529,12 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN
[self refreshLocalContacts];
_isAppForeground = YES;
if (@available(iOS 11.0, *))
{
// Riot has its own dark theme. Prevent iOS from applying its one
[[UIApplication sharedApplication] keyWindow].accessibilityIgnoresInvertColors = YES;
}
[self handleLaunchAnimation];
}
@ -1817,7 +1820,7 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN
[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)

View file

@ -416,9 +416,18 @@
"auth_email_not_found" = "Fehler beim Senden der E-Mail: Die E-Mail-Adresse wurde nicht gefunden";
"settings_user_interface" = "BENUTZEROBERFLÄCHE";
"settings_ui_language" = "Sprache";
"settings_ui_light_theme" = "Helles Design";
"settings_ui_dark_theme" = "Dunkles Design";
// Events formatter
"event_formatter_member_updates" = "%tu Änderungen der Mitgliedschaft";
"contacts_user_directory_section" = "NUTZER VERZEICHNIS";
"contacts_user_directory_offline_section" = "NUTZER VERZEICHNIS (offline)";
"auth_home_server_placeholder" = "URL (z.B. https://matrix.org)";
"auth_identity_server_placeholder" = "URL (z.B. https://matrix.org)";
"room_ongoing_conference_call_close" = "Schließen";
"room_conference_call_no_power" = "Du brauchst die Berechtigung Konferenzgespräche in diesem Raum zu verwalten";
"settings_labs_create_conference_with_jitsi" = "Erstelle Konferenzgespräche mit Jitsi";
"call_already_displayed" = "Es existiert bereits ein Gespräch.";
"call_jitsi_error" = "Konferenzgespräch konnte nicht betreten werden.";
// Widget
"widget_no_power_to_manage" = "Du brauchst die Berechtigung um Widgets in diesem Raum zu verwalten";
"widget_creation_failure" = "Widget-Erstellung fehlgeschlagen";
"room_ongoing_conference_call_with_close" = "Laufendes Konferenzgespräch. Trete mit %@ oder %@ bei. %@ es.";

View file

@ -106,7 +106,6 @@
"auth_reset_password_error_not_found" = "Your email address does not appear to be associated with a Matrix ID on this Homeserver.";
"auth_reset_password_success_message" = "Your password has been reset.\n\nYou have been logged out of all devices and will no longer receive push notifications. To re-enable notifications, re-log in on each device.";
"auth_add_email_and_phone_warning" = "Registration with email and phone number at once is not supported yet until the api exists. Only the phone number will be taken into account. You may add your email to your profile in settings.";
"auth_share_extension_prompt" = "Login in the main app to share content";
// Chat creation
"room_creation_title" = "New Chat";
@ -344,8 +343,12 @@
"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_light_theme" = "Light theme";
"settings_ui_dark_theme" = "Dark theme";
"settings_ui_theme" = "Theme";
"settings_ui_theme_auto" = "Auto";
"settings_ui_theme_light" = "Light";
"settings_ui_theme_dark" = "Dark";
"settings_ui_theme_picker_title" = "Select a theme";
"settings_ui_theme_picker_message" = "\"Auto\" uses your device \"Invert Colours\" settings";
"settings_unignore_user" = "Show all messages from %@?";
@ -367,6 +370,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";
@ -460,6 +464,8 @@
// Events formatter
"event_formatter_member_updates" = "%tu membership changes";
"event_formatter_widget_added" = "%@ widget added by %@";
"event_formatter_widget_removed" = "%@ widget removed by %@";
"event_formatter_jitsi_widget_added" = "VoIP conference added by %@";
"event_formatter_jitsi_widget_removed" = "VoIP conference removed by %@";
@ -472,6 +478,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";
@ -529,3 +536,7 @@
"widget_integration_missing_user_id" = "Missing user_id in request.";
"widget_integration_room_not_visible" = "Room %@ is not visible.";
// Share extension
"share_extension_auth_prompt" = "Login in the main app to share content";
"share_extension_failed_to_encrypt" = "Failed to send. Check in the main app the encryption settings for this room";

View file

@ -2,3 +2,45 @@
"title_home" = "Inicio";
"title_favourites" = "Favoritos";
"title_people" = "Contactos";
"title_rooms" = "Salas";
"warning" = "Atención";
// Actions
"view" = "Ver";
"next" = "SIguiente";
"back" = "Anterior";
"continue" = "Continuar";
"create" = "Crear";
"start" = "Iniciar";
"leave" = "Salir";
"remove" = "Remover";
"invite" = "Invitar";
"retry" = "Re-intentar";
"on" = "Activado";
"off" = "Desactivado";
"cancel" = "Cancelar";
"save" = "Guardar";
"join" = "Entrar";
"decline" = "Rechazar";
"accept" = "Aceptar";
"preview" = "Vista previa";
"camera" = "Cámara";
"voice" = "Voz";
"video" = "Vídeo";
"active_call" = "Llamada activa";
"active_call_details" = "Llamada activa (%@)";
"later" = "Después";
"rename" = "Renombrar";
"collapse" = "colapsar";
// Authentication
"auth_login" = "Ingresar";
"auth_register" = "Registrar";
"auth_submit" = "Enviar";
"auth_skip" = "Omitir";
"auth_send_reset_email" = "Enviar Email de restauración";
"auth_return_to_login" = "Regresar a pantalla de ingreso";
"auth_user_id_placeholder" = "Email o nombre de usuario";
"auth_password_placeholder" = "Contraseña";
"auth_new_password_placeholder" = "Nueva contraseña";
"auth_user_name_placeholder" = "Nombre de usuario";
"auth_optional_email_placeholder" = "Dirección de Email (opcional)";
"auth_email_placeholder" = "Dirección Email";

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

@ -422,3 +422,14 @@
"bug_report_progress_zipping" = "Egunkariak biltzen";
"bug_report_progress_uploading" = "Txostena igotzen";
"room_details_advanced_e2e_encryption_prompt_message" = "Muturretik muturrerako zifratzea esperimentala da eta agian ez dabil behar bezala.\n\nEz zenuke datuak babesteko erabili behar oraindik.\n\nGailuek ezin izango dute gelara elakrtu aurreko historiala deszifratu.\n\nBehin gela batean zifratzea aktibatuta ez dago gero desaktibatzerik (oraingoz).\n\nZifratutako mezuak ezin izango dira ikusi oraindik zifratzea onartzen ez duten bezeroetan.";
"auth_home_server_placeholder" = "URL (adib. https://matrix.org)";
"auth_identity_server_placeholder" = "URL (adib. https://matrix.org)";
"room_ongoing_conference_call_with_close" = "Konferentzia deia abian. elkartu %@ edo %@ gisa. %@.";
"room_ongoing_conference_call_close" = "Itxi";
"room_conference_call_no_power" = "Baimena behar duzu konferentzia deia kudeatzeko gela honetan";
"settings_labs_create_conference_with_jitsi" = "Sortu konferentzia deia jitsi erabiliz";
"call_already_displayed" = "Badago de bat abian.";
"call_jitsi_error" = "Hutsegitea konferentzia deia elkartzean.";
// Widget
"widget_no_power_to_manage" = "Baimena behar duzu trepetak kudeatzeko gela honetan";
"widget_creation_failure" = "Trepetaren sorrerak huts egin du";

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

@ -20,7 +20,7 @@
"decline" = "Refuser";
"accept" = "Accepter";
"preview" = "Aperçu";
"camera" = "Caméra";
"camera" = "Appareil photo";
"voice" = "Voix";
"video" = "Vidéo";
"active_call" = "Appel en cours";
@ -28,12 +28,12 @@
"later" = "Plus tard";
"rename" = "Renommer";
// Authentication
"auth_login" = "Identification";
"auth_register" = "Inscription";
"auth_login" = "Se connecter";
"auth_register" = "S'inscrire";
"auth_submit" = "Valider";
"auth_skip" = "Ignorer";
"auth_send_reset_email" = "Envoyer un e-mail de réinitialisation";
"auth_return_to_login" = "Retour à l'identification";
"auth_return_to_login" = "Retour à l'écran de connexion";
"auth_user_id_placeholder" = "E-mail ou nom d'utilisateur";
"auth_password_placeholder" = "Mot de passe";
"auth_new_password_placeholder" = "Nouveau mot de passe";
@ -42,27 +42,27 @@
"auth_email_placeholder" = "Adresse e-mail";
"auth_optional_phone_placeholder" = "Numéro de téléphone (facultatif)";
"auth_phone_placeholder" = "Numéro de téléphone";
"auth_repeat_password_placeholder" = "Recopier le mot de passe";
"auth_repeat_password_placeholder" = "Répéter le mot de passe";
"auth_repeat_new_password_placeholder" = "Confirmer le nouveau mot de passe";
"auth_invalid_login_param" = "Nom d'utilisateur ou mot de passe incorrect";
"auth_invalid_user_name" = "Les noms d'utilisateur ne peuvent contenir que des lettres, chiffres, points, tirets haut ou bas";
"auth_invalid_login_param" = "Nom d'utilisateur et/ou mot de passe incorrect";
"auth_invalid_user_name" = "Les noms d'utilisateur ne peuvent contenir que des lettres, des chiffres, des points, des traits d'union ou des tirets bas";
"auth_invalid_password" = "Mot de passe trop court (min 6)";
"auth_invalid_email" = "L'adresse e-mail ne semble pas valide";
"auth_invalid_phone" = "Le numéro de téléphone ne semble pas valide";
"auth_missing_password" = "Mot de passe manquant";
"auth_add_email_message" = "Ajouter une adresse e-mail au compte pour que les utilisateurs vous retrouvent, et pour récupérer votre mot de passe.";
"auth_add_phone_message" = "Ajouter un numéro de téléphone pour que les utilisateurs vous retrouvent.";
"auth_add_email_phone_message" = "Ajouter une adresse e-mail et/ou un numéro de téléphone à votre compte pour que les utilisateurs vous retrouvent. L'adresse e-mail permettra également de réinitialiser votre mot de passe.";
"auth_add_email_and_phone_message" = "Ajouter une adresse e-mail et un numéro de téléphone à votre compte pour que les utilisateurs vous retrouvent. L'adresse e-mail permettra également de réinitialiser votre mot de passe.";
"auth_add_email_message" = "Ajouter une adresse e-mail au compte pour que les utilisateurs puissent vous retrouver, et pour pouvoir réinitialiser votre mot de passe.";
"auth_add_phone_message" = "Ajouter un numéro de téléphone au compte pour que les utilisateurs puissent vous retrouver.";
"auth_add_email_phone_message" = "Ajouter une adresse e-mail et/ou un numéro de téléphone à votre compte pour que les utilisateurs puissent vous retrouver. L'adresse e-mail vous permettra également de réinitialiser votre mot de passe.";
"auth_add_email_and_phone_message" = "Ajouter une adresse e-mail et un numéro de téléphone à votre compte pour que les utilisateurs puissent vous retrouver. L'adresse e-mail vous permettra également de réinitialiser votre mot de passe.";
"auth_missing_email" = "Adresse e-mail manquante";
"auth_missing_phone" = "Numéro de téléphone manquant";
"auth_missing_email_or_phone" = "Adresse e-mail ou numéro de téléphone manquant";
"auth_password_dont_match" = "Les mots de passe ne correspondent pas";
"auth_username_in_use" = "L'identifiant est déjà utilisé";
"auth_forgot_password" = "Mot de passe oublié ?";
"auth_use_server_options" = "Utiliser un serveur spécifique (avancé)";
"auth_use_server_options" = "Utiliser un serveur personnalisé (avancé)";
"auth_email_validation_message" = "Merci de vérifier vos e-mails pour continuer l'inscription";
"auth_msisdn_validation_title" = "Vérification en cours";
"auth_msisdn_validation_title" = "Vérification en attente";
"auth_msisdn_validation_message" = "Nous vous avons envoyé un SMS avec un code d'activation. Merci de le recopier ci-dessous.";
"auth_msisdn_validation_error" = "Impossible de vérifier votre numéro de téléphone.";
"auth_reset_password_message" = "Pour réinitialiser votre mot de passe, saisissez l'adresse e-mail liée à votre compte :";
@ -71,24 +71,24 @@
"auth_reset_password_email_validation_message" = "Un e-mail a été envoyé à %@. Cliquez d'abord sur le lien dans l'e-mail, puis ci-dessous.";
"auth_reset_password_next_step_button" = "J'ai vérifié mon adresse e-mail";
"auth_reset_password_error_unauthorized" = "Impossible de vérifier l'adresse e-mail : assurez-vous de cliquer sur le lien dans l'e-mail";
"auth_reset_password_error_not_found" = "Votre adresse e-mail ne semble pas associée à un identificant Matrix sur ce serveur.";
"auth_reset_password_success_message" = "Votre mot de passe a été réinitialisé.\n\nVous avez été déconnecté de tous vos appareils et ne recevrez plus les notifications. Pour réactiver les notifications, identifiez-vous à nouveau sur chaque appareil.";
"auth_add_email_and_phone_warning" = "Enregistrer un e-mail et un numéro de téléphone en une seule fois n'est pas supporté tant que l'api n'existe pas. Seul votre numéro de téléphone sera pris en compte. Vous pourrez ajouter l'adresse e-mail dans vos options de profil.";
"auth_reset_password_error_not_found" = "Votre adresse e-mail ne semble pas associée à un identifiant Matrix sur ce serveur d'accueil.";
"auth_reset_password_success_message" = "Votre mot de passe a été réinitialisé.\n\nVous avez été déconnecté de tous vos appareils et ne recevrez plus les notifications. Pour réactiver les notifications, reconnectez-vous sur chaque appareil.";
"auth_add_email_and_phone_warning" = "L'inscription avec un e-mail et un numéro de téléphone à la fois n'est pas supporté tant que l'API n'existe pas. Seul votre numéro de téléphone sera pris en compte. Vous pourrez ajouter l'adresse e-mail dans vos options de profil.";
// Chat creation
"room_creation_title" = "Nouvelle discussion";
"room_creation_account" = "Compte";
"room_creation_appearance" = "Apparence";
"room_creation_appearance_name" = "Nom";
"room_creation_appearance_picture" = "Vignette (facultatif)";
"room_creation_appearance_picture" = "Avatar du salon (facultatif)";
"room_creation_private_room" = "Cette discussion est privée";
"room_creation_public_room" = "Cette discussion est publique";
"room_creation_make_public" = "Rendre publique";
"room_creation_make_public_prompt_title" = "Voulez-vous rendre cette discussion publique ?";
"room_creation_make_public_prompt_msg" = "Êtes-vous sûr de vouloir rendre cette discussion publique ? Tout le monde pourra lire vos messages et rejoindre la discussion.";
"room_creation_make_public_prompt_msg" = "Voulez-vous vraiment rendre cette discussion publique ? Tout le monde pourra lire vos messages et rejoindre la discussion.";
"room_creation_keep_private" = "Garder privée";
"room_creation_make_private" = "Rendre privée";
"room_creation_wait_for_creation" = "Un salon est déjà créé, merci de patienter.";
"room_creation_invite_another_user" = "Rechercher / inviter par identifiant, nom ou e-mail";
"room_creation_wait_for_creation" = "Un salon est déjà en cours de création. Veuillez patienter.";
"room_creation_invite_another_user" = "Rechercher/inviter par identifiant, nom ou e-mail";
// Room recents
"room_recents_directory_section" = "RÉPERTOIRE DES SALONS";
"room_recents_directory_section_network" = "Réseau";
@ -98,11 +98,11 @@
"room_recents_no_conversation" = "Aucun salon";
"room_recents_low_priority_section" = "PRIORITÉ BASSE";
"room_recents_invites_section" = "INVITATIONS";
"room_recents_start_chat_with" = "Nouvelle discussion";
"room_recents_start_chat_with" = "Commencer une discussion";
"room_recents_create_empty_room" = "Créer un salon";
"room_recents_join_room" = "Rejoindre le salon";
"room_recents_join_room_title" = "Rejoindre un salon";
"room_recents_join_room_prompt" = "Saisir un identifiant ou une adresse de salon";
"room_recents_join_room_prompt" = "Saisir un identifiant ou un alias de salon";
// People tab
"people_invites_section" = "INVITATIONS";
"people_conversation_section" = "DISCUSSIONS";
@ -120,9 +120,9 @@
// Directory
"directory_cell_title" = "Parcourir le répertoire";
"directory_cell_description" = "%tu salons";
"directory_search_results_title" = "Résultats dans le répertoire";
"directory_search_results_title" = "Parcourir les résultats dans le répertoire";
"directory_search_results" = "%tu résultats trouvés pour %@";
"directory_search_results_more_than" = "> %tu résultats trouvés pour %@";
"directory_search_results_more_than" = ">%tu résultats trouvés pour %@";
"directory_searching_title" = "Recherche dans le répertoire…";
"directory_search_fail" = "Impossible de récupérer les données";
// Contacts
@ -139,21 +139,21 @@
"room_participants_one_participant" = "1 membre";
"room_participants_multi_participants" = "%d membres";
"room_participants_leave_prompt_title" = "Quitter le salon";
"room_participants_leave_prompt_msg" = "Êtes-vous sûr de vouloir quitter le salon ?";
"room_participants_leave_prompt_msg" = "Voulez-vous vraiment quitter le salon ?";
"room_participants_remove_prompt_title" = "Confirmation";
"room_participants_remove_prompt_msg" = "Êtes-vous sûr de vouloir exclure %@ du ce salon ?";
"room_participants_remove_prompt_msg" = "Voulez-vous vraiment exclure %@ de ce salon ?";
"room_participants_invite_prompt_title" = "Confirmation";
"room_participants_invite_prompt_msg" = "Êtes-vous sûr de vouloir inviter %@ sur ce salon ?";
"room_participants_filter_room_members" = "Filtrer les membres";
"room_participants_invite_another_user" = "Rechercher / inviter par identifiant, nom ou e-mail";
"room_participants_invite_prompt_msg" = "Voulez-vous vraiment inviter %@ dans ce salon ?";
"room_participants_filter_room_members" = "Filtrer les membres du salon";
"room_participants_invite_another_user" = "Rechercher/inviter par identifiant, nom ou e-mail";
"room_participants_invite_malformed_id_title" = "Erreur lors de l'invitation";
"start" = "Démarrer";
"start" = "Commencer";
"on" = "Activé";
"off" = "Désactivé";
"auth_recaptcha_message" = "Ce homeserver voudrait s'assurer que vous n'êtes pas un robot";
"auth_recaptcha_message" = "Ce serveur d'accueil voudrait s'assurer que vous n'êtes pas un robot";
"room_creation_privacy" = "Visibilité";
"room_participants_remove_third_party_invite_msg" = "Supprimer une invitation de tiers n'est pas encore supporter tant que l'api n'existe pas";
"room_participants_invite_malformed_id" = "Identifiant au mauvais format. Une adresse e-mail ou un identifiant Matrix au format '@utilisateur:domaine' est attendu";
"room_participants_remove_third_party_invite_msg" = "Supprimer une invitation de tiers n'est pas prise en charge tant que l'API n'existe pas";
"room_participants_invite_malformed_id" = "Identifiant au mauvais format. Une adresse e-mail ou un identifiant Matrix au format \"@utilisateur:domaine\" est attendu";
"room_participants_invited_section" = "INVITÉS";
"room_participants_online" = "En ligne";
"room_participants_offline" = "Hors ligne";
@ -169,32 +169,32 @@
"room_participants_action_leave" = "Quitter ce salon";
"room_participants_action_remove" = "Exclure de ce salon";
"room_participants_action_ban" = "Bannir de ce salon";
"room_participants_action_unban" = "Amnistier";
"room_participants_action_unban" = "Révoquer le bannissement";
"room_participants_action_ignore" = "Masquer tous les messages de cet utilisateur";
"room_participants_action_unignore" = "Afficher tous les messages de cet utilisateur";
"room_participants_action_set_default_power_level" = "Réinitialiser au niveau normal";
"room_participants_action_set_moderator" = "Promouvoir modérateur";
"room_participants_action_set_admin" = "Promouvoir administrateur";
"room_participants_action_start_new_chat" = "Nouvelle discussion";
"room_participants_action_start_voice_call" = "Nouvel appel vocal";
"room_participants_action_start_video_call" = "Nouvel appel vidéo";
"room_participants_action_set_default_power_level" = "Rétrograder en utilisateur normal";
"room_participants_action_set_moderator" = "Nommer modérateur";
"room_participants_action_set_admin" = "Nommer administrateur";
"room_participants_action_start_new_chat" = "Commencer une nouvelle discussion";
"room_participants_action_start_voice_call" = "Commencer un appel vocal";
"room_participants_action_start_video_call" = "Commencer un appel vidéo";
"room_participants_action_mention" = "Mentionner";
// Chat
"room_jump_to_first_unread" = "Aller au premier message non lu";
"room_new_message_notification" = "%d nouveau message";
"room_new_messages_notification" = "%d nouveaux messages";
"room_one_user_is_typing" = "%@ est en train d'écrire…";
"room_two_users_are_typing" = "%@ et %@ sont en train d'écrire…";
"room_many_users_are_typing" = "%@, %@ et d'autres sont en train d'écrire…";
"room_one_user_is_typing" = "%@ écrit…";
"room_two_users_are_typing" = "%@ et %@ écrivent…";
"room_many_users_are_typing" = "%@, %@ et d'autres écrivent…";
"room_message_placeholder" = "Envoyer un message (non chiffré)…";
"encrypted_room_message_placeholder" = "Envoyer un message chiffré…";
"room_message_short_placeholder" = "Envoyer un message…";
"room_offline_notification" = "La connectivité au serveur a été perdue.";
"room_offline_notification" = "La connexion au serveur a été perdue.";
"room_unsent_messages_notification" = "Messages non envoyés. %@ ou %@ maintenant ?";
"room_unsent_messages_unknown_devices_notification" = "Message non envoyé car des appareils inconnus sont présents. %@ ou %@ maintenant ?";
"room_ongoing_conference_call" = "Conférence en cours. Rejoindre en %@ ou %@.";
"room_ongoing_conference_call" = "Téléconférence en cours. Rejoindre en %@ ou %@.";
"room_prompt_resend" = "Tout renvoyer";
"room_prompt_cancel" = "Tout annuler";
"room_prompt_cancel" = "tout annuler";
"room_resend_unsent_messages" = "Renvoyer les messages non envoyés";
"room_delete_unsent_messages" = "Supprimer les messages non envoyés";
"room_event_action_copy" = "Copier";
@ -205,18 +205,18 @@
"room_event_action_permalink" = "Permalien";
"room_event_action_view_source" = "Voir la source";
"room_event_action_report" = "Signaler le contenu";
"room_event_action_report_prompt_reason" = "Raison pour signaler le contenu";
"room_event_action_report_prompt_reason" = "Raison pour le signalement du contenu";
"room_event_action_report_prompt_ignore_user" = "Voulez-vous masquer tous les messages de cet utilisateur ?";
"room_event_action_save" = "Enregistrer";
"room_event_action_resend" = "Renvoyer";
"room_event_action_delete" = "Supprimer";
"room_event_action_cancel_upload" = "Annuler le téléchargement";
"room_event_action_cancel_upload" = "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 bêta et peut ne pas être fiable.\n\nIl ne devrait pas être considéré comme de confiance pour sécuriser les données.\n\nLes appareils ne peuvent pas encore déchiffrer l'historique avant leur adhésion au salon.\n\nLes messages chiffrés ne peuvent pas être lus pas les clients qui n'implémentent pas 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.";
// Unknown devices
"unknown_devices_alert_title" = "Le salon contient des appareils inconnus";
"unknown_devices_alert" = "Ce salon contient des appareils inconnus qui n'ont pas été vérifiés.\nCela signifie qu'il n'y a pas de garantie que ces appareils appartiennent aux utilisateurs déclarés.\nNous recommendons d'effectuer le processus de vérification pour chaque appareil avant de continuer, mais vous pouvez renvoyer les message sans vérifier si vous préférez.";
"unknown_devices_alert" = "Ce salon contient des appareils inconnus qui n'ont pas été vérifiés.\nCela signifie qu'il n'y a aucune garantie que les appareils appartiennent aux utilisateurs qu'ils prétendent.\nNous vous recommandons d'effectuer le processus de vérification pour chaque appareil avant de continuer, mais vous pouvez renvoyer le message sans vérifier si vous préférez.";
"unknown_devices_send_anyway" = "Envoyer quand même";
"unknown_devices_call_anyway" = "Appeler quand même";
"unknown_devices_answer_anyway" = "Répondre quand même";
@ -230,51 +230,51 @@
"room_title_members" = "%@ membres";
"room_title_one_member" = "1 membre";
// Room Preview
"room_preview_invitation_format" = "Vous avez été invité à rejoindre ce salon par %@";
"room_preview_invitation_format" = "Vous avez été invité(e) à rejoindre ce salon par %@";
"room_preview_subtitle" = "Ceci est un aperçu du salon. Les interactions avec le salon sont désactivées.";
"room_preview_unlinked_email_warning" = "Cette invitation a été envoyée à %@, qui n'est pas associé avec ce compte. Vous pouvez vous identifier avec un compte différent ou ajouter cette adresse e-mail à ce compte.";
"room_preview_try_join_an_unknown_room" = "Vous essayez d'accéder à %@. Voulez-vous rejoindre afin de participer à la discussion ?";
"room_preview_unlinked_email_warning" = "Cette invitation a été envoyée à %@, qui n'est pas associé à ce compte. Vous pouvez vous identifier avec un compte différent ou ajouter cette adresse e-mail à ce compte.";
"room_preview_try_join_an_unknown_room" = "Vous essayez d'accéder à %@. Voulez-vous rejoindre la discussion afin d'y participer ?";
"room_preview_try_join_an_unknown_room_default" = "un salon";
// Settings
"settings_title" = "Paramètres";
"account_logout_all" = "Déconnecter tous les comptes";
"settings_config_no_build_info" = "Aucune information sur le build";
"settings_config_no_build_info" = "Aucune information sur la version";
"settings_mark_all_as_read" = "Marquer tous les messages comme lus";
"settings_report_bug" = "Signaler une erreur";
"settings_config_home_server" = "Le homeserver est %@";
"settings_config_home_server" = "Le serveur d'accueil est %@";
"settings_config_identity_server" = "Le serveur d'identité est %@";
"settings_config_user_id" = "Identifié en tant que %@";
"settings_user_settings" = "PRÉFÉRENCES UTILISATEUR";
"settings_notifications_settings" = "PRÉFÉRENCES DE NOTIFICATIONS";
"settings_ignored_users" = "UTILISATEURS IGNORÉS";
"settings_contacts" = "CONTACT LOCAUX";
"settings_contacts" = "CONTACTS LOCAUX";
"settings_advanced" = "AVANCÉ";
"settings_other" = "AUTRES";
"settings_labs" = "LABORATOIRE";
"settings_devices" = "APPAREILS";
"settings_cryptography" = "CHIFFREMENT";
"settings_sign_out" = "Se déconnecter";
"settings_sign_out_confirmation" = "Êtes-vous sûr ?";
"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 sur les salons chiffrés depuis cet appreil.";
"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 d'affichage";
"settings_first_name" = "Prénom";
"settings_surname" = "Nom de famille";
"settings_surname" = "Nom";
"settings_remove_prompt_title" = "Confirmation";
"settings_remove_email_prompt_msg" = "Êtes-vous sûr de vouloir supprimer l'adresse e-mail %@ ?";
"settings_remove_phone_prompt_msg" = "Êtes-vous sûr de vouloir supprimer le numéro de téléphone %@ ?";
"settings_remove_email_prompt_msg" = "Voulez-vous vraiment supprimer l'adresse e-mail %@ ?";
"settings_remove_phone_prompt_msg" = "Voulez-vous vraiment supprimer le numéro de téléphone %@ ?";
"settings_email_address" = "E-mail";
"settings_email_address_placeholder" = "Entrer votre adresse e-mail";
"settings_email_address_placeholder" = "Saisir votre adresse e-mail";
"settings_add_email_address" = "Ajouter une adresse e-mail";
"settings_phone_number" = "Téléphone";
"settings_add_phone_number" = "Ajouter un numéro de téléphone";
"settings_night_mode" = "Mode nuit";
"settings_fail_to_update_profile" = "Impossible de mettre à jour le profil";
"settings_fail_to_update_profile" = "Échec de la mise à jour du profil";
"settings_enable_push_notif" = "Notifications sur cet appareil";
"settings_global_settings_info" = "Les paramètres de notification globaux sont disponibles sur votre client web %@";
"settings_pin_rooms_with_missed_notif" = "Épingler les salons avec des notifications non lues";
"settings_pin_rooms_with_unread" = "Épingler les salons avec des messages non lus";
"settings_on_denied_notification" = "Les notifications sont refusées pour %@, merci de les autoriser dans les préférences de votre appareil";
"settings_on_denied_notification" = "Les notifications sont refusées pour %@, merci de les autoriser dans les paramètres de votre appareil";
"settings_unignore_user" = "Afficher tous les messages de %@ ?";
"settings_contacts_discover_matrix_users" = "Utiliser un e-mail ou un numéro de téléphone pour retrouver des utilisateurs";
"settings_contacts_phonebook_country" = "Pays pour le répertoire téléphonique";
@ -290,18 +290,19 @@
"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";
"settings_new_password" = "nouveau mot de passe";
"settings_confirm_password" = "confirmer le mot de passe";
"settings_fail_to_update_password" = "Impossible de changer le mot de passe";
"settings_password_updated" = "Votre mot de passe a été changé";
"settings_crypto_device_name" = "Nom d'appareil : ";
"settings_crypto_device_id" = "\nIdentifiant d'appareil : ";
"settings_crypto_device_key" = "\nClé d'appareil : ";
"settings_fail_to_update_password" = "Échec de la modification du mot de passe";
"settings_password_updated" = "Votre mot de passe a été modifié";
"settings_crypto_device_name" = "Nom de l'appareil : ";
"settings_crypto_device_id" = "\nIdentifiant de l'appareil : ";
"settings_crypto_device_key" = "\nClé de l'appareil : ";
"settings_crypto_export" = "Exporter les clés";
"settings_crypto_blacklist_unverified_devices" = "Chiffrer vers les appareils vérifiés uniquement";
"settings_crypto_blacklist_unverified_devices" = "Chiffrer uniquement vers les appareils vérifiés";
// Room Details
"room_details_title" = "Détails du salon";
"room_details_people" = "Membres";
@ -315,75 +316,76 @@
"room_details_mute_notifs" = "Désactiver les notifications";
"room_details_direct_chat" = "Discussion directe";
"room_details_access_section" = "Qui peut accéder à ce salon ?";
"room_details_access_section_invited_only" = "Seulement les personnes qui ont été invitées";
"room_details_access_section_anyone_apart_from_guest" = "N'importe qui ayant un lien vers le salon, hormis les visiteurs";
"room_details_access_section_anyone" = "N'importe qui ayant un lien vers le salon, y compris les invités";
"room_details_access_section_no_address_warning" = "Pour référencer le salon, il doit avoir une adresse";
"room_details_access_section_invited_only" = "Seules les personnes qui ont été invitées";
"room_details_access_section_anyone_apart_from_guest" = "Tous ceux qui connaissent le lien du salon, à part les visiteurs";
"room_details_access_section_anyone" = "Tous ceux qui connaissent le lien du salon, y compris les visiteurs";
"room_details_access_section_no_address_warning" = "Pour récupérer le lien vers un salon, celui-ci doit avoir une adresse";
"room_details_access_section_directory_toggle" = "Lister ce salon dans le répertoire des salons";
"room_details_history_section" = "Qui peut lire l'historique ?";
"room_details_history_section_anyone" = "N'importe qui";
"room_details_history_section_members_only" = "Les membres uniquements (depuis le moment où cette option est sélectionnée)";
"room_details_history_section_members_only_since_invited" = "Les membres uniquement (depuis qu'ils ont été invité)";
"room_details_history_section_members_only_since_joined" = "Les membres uniquement (depuis qu'ils ont rejoint)";
"room_details_history_section_members_only" = "Uniquement les membres (à partir de l'activation de cette option)";
"room_details_history_section_members_only_since_invited" = "Uniquement les membres (depuis leur invitation)";
"room_details_history_section_members_only_since_joined" = "Uniquement les membres (depuis qu'ils sont arrivés)";
"room_details_history_section_prompt_title" = "Alerte de confidentialité";
"room_details_history_section_prompt_msg" = "Les changements d'accès à l'historique ne s'appliqueront qu'aux futurs messages. La visibilité de l'historique actuel demeurera inchangée.";
"room_details_history_section_prompt_msg" = "Les changements d'accès à l'historique ne s'appliqueront qu'aux futurs messages du salon. La visibilité de l'historique existant demeurera inchangée.";
"room_details_addresses_section" = "Adresses";
"room_details_no_local_addresses" = "Ce salon n'a pas d'adresse locale";
"room_details_new_address" = "Ajouter une adresse";
"room_details_new_address_placeholder" = "Ajouter une adresse (par ex. #foo%@)";
"room_details_addresses_invalid_address_prompt_title" = "Format d'adresse invalide";
"room_details_addresses_invalid_address_prompt_title" = "Format d'alias non valide";
"room_details_addresses_invalid_address_prompt_msg" = "%@ n'est pas un format valide pour un alias";
"room_details_addresses_disable_main_address_prompt_title" = "Alerte sur l'adresse principale";
"room_details_addresses_disable_main_address_prompt_msg" = "Vous n'aurez aucune adresse principale spécifiée. L'adresse principale par défaut de ce salon sera choisie aléatoirement";
"room_details_banned_users_section" = "Utilisateurs bannis";
"room_details_advanced_section" = "Avancé";
"room_details_advanced_room_id" = "Identifiant de salon :";
"room_details_advanced_room_id" = "Identifiant du salon :";
"room_details_advanced_enable_e2e_encryption" = "Activer le chiffrement (attention : ne peut pas être désactivé !)";
"room_details_advanced_e2e_encryption_enabled" = "Le chiffrement est activé sur ce salon";
"room_details_advanced_e2e_encryption_disabled" = "Le chiffrement est désactivé sur ce salon.";
"room_details_advanced_e2e_encryption_blacklist_unverified_devices" = "Chiffrer vers les appareils vérifiés uniquement";
"room_details_advanced_e2e_encryption_prompt_message" = "Le chiffrement de bout en bout est en bêta et peut ne pas être fiable.\n\nIl ne devrait pas être considéré comme de confiance pour sécuriser les données.\n\nLes appareils ne peuvent pas encore déchiffrer l'historique avant leur adhésion au salon.\n\nUne fois le chiffrement activé pour un salon, il ne peut plus être désactivé (pour l'instant).\n\nLes messages chiffrés ne peuvents pas être lus pas les clients qui n'implémentent pas le chiffrement.";
"room_details_fail_to_update_avatar" = "Impossible de modifier l'image du salon";
"room_details_fail_to_update_room_name" = "Impossible de modifier le nom du salon";
"room_details_fail_to_update_topic" = "Impossible de modifier le sujet";
"room_details_fail_to_update_room_guest_access" = "Impossible de modifier les accès visiteur pour le salon";
"room_details_fail_to_update_room_join_rule" = "Impossible de modifier les règles pour rejoindre";
"room_details_fail_to_update_room_directory_visibility" = "Impossible de modifier la visibilité du salon dans le répertoire";
"room_details_fail_to_update_history_visibility" = "Impossible de modifier la visibilité de l'historique";
"room_details_fail_to_add_room_aliases" = "Impossible d'ajouter les nouvelles adresses au salon";
"room_details_fail_to_remove_room_aliases" = "Impossible de supprimer les adresses du salon";
"room_details_fail_to_update_room_canonical_alias" = "Impossible de modifier l'adresse principale";
"room_details_fail_to_update_room_direct" = "Impossible de modifier l'état de discussion directe";
"room_details_fail_to_enable_encryption" = "Impossible d'activer le chiffrement sur ce salon";
"room_details_save_changes_prompt" = "Voulez-vous enregistrer les changements ?";
"room_details_set_main_address" = "Configurer comme adresse principale";
"room_details_advanced_e2e_encryption_blacklist_unverified_devices" = "Chiffrer uniquement vers les appareils vérifiés";
"room_details_advanced_e2e_encryption_prompt_message" = "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\nUne fois le chiffrement activé pour un salon, il ne peut plus être désactivé (pour l'instant).\n\nLes messages chiffrés ne seront pas visibles sur les clients qui n'ont pas encore implémenté le chiffrement.";
"room_details_fail_to_update_avatar" = "Échec de mise à jour de l'image du salon";
"room_details_fail_to_update_room_name" = "Échec de mise à jour du nom du salon";
"room_details_fail_to_update_topic" = "Échec de mise à jour du sujet";
"room_details_fail_to_update_room_guest_access" = "Échec de mise à jour de l'accès au salon pour les visiteurs";
"room_details_fail_to_update_room_join_rule" = "Échec de mise à jour des règles pour rejoindre le salon";
"room_details_fail_to_update_room_directory_visibility" = "Échec de mise à jour de la visibilité du salon dans le répertoire";
"room_details_fail_to_update_history_visibility" = "Échec de mise à jour de la visibilité de l'historique";
"room_details_fail_to_add_room_aliases" = "Échec de l'ajout des nouvelles adresses du salon";
"room_details_fail_to_remove_room_aliases" = "Échec de la suppression des adresses du salon";
"room_details_fail_to_update_room_canonical_alias" = "Échec de la mise à jour de l'adresse principale";
"room_details_fail_to_update_room_direct" = "Échec de mise à jour de l'étiquette de discussion directe";
"room_details_fail_to_enable_encryption" = "Échec de l'activation du chiffrement de ce salon";
"room_details_save_changes_prompt" = "Voulez-vous enregistrer les modifications ?";
"room_details_set_main_address" = "Définir comme adresse principale";
"room_details_unset_main_address" = "Désactiver comme adresse principale";
"room_details_copy_room_id" = "Copier l'identifiant du salon";
"room_details_copy_room_address" = "Copier l'adresse du salon";
"room_details_copy_room_url" = "Copier l'URL du salon";
"room_details_copy_room_url" = "Copier le lien du salon";
// Read Receipts
"read_receipts_list" = "Liste des accusés de lecture";
"receipt_status_read" = "Lu : ";
// Media picker
"media_picker_library" = "Bibliothèque";
"media_picker_library" = "Médiathèque";
"media_picker_select" = "Sélectionner";
// Directory
"directory_title" = "Répertoire";
"directory_server_picker_title" = "Sélectionner un répertoire";
"directory_server_all_rooms" = "Tous les salons sur le serveur %@";
"directory_server_all_native_rooms" = "Tous les salons Matrix natifs";
"directory_server_type_homeserver" = "Saisir un homeserver pour lister ses salons publics";
"directory_server_type_homeserver" = "Saisir un serveur d'accueil pour lister ses salons publics";
"directory_server_placeholder" = "matrix.org";
// Others
"or" = "ou";
"you" = "Vous";
"today" = "Aujourd'hui";
"yesterday" = "Hier";
"network_offline_prompt" = "La connection Internet semble hors-ligne.";
"network_offline_prompt" = "La connexion Internet semble être hors-ligne.";
"public_room_section_title" = "Salons publics (sur %@) :";
"bug_report_prompt" = "L'application a terminé en erreur la dernière fois. Voulez-vous envoyer un rapport d'erreur ?";
"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 ?";
"camera_access_not_granted" = "%@ n'a pas les permissions pour utiliser la caméra, merci de modifier les options de vie privée";
"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
"room_displayname_invite_from" = "Invitation de %@";
@ -392,7 +394,7 @@
"room_displayname_more_than_two_members" = "%@ et %u autres";
"room_displayname_no_title" = "Salon vide";
// Call
"call_incoming_voice_prompt" = "Appel audio entrant de %@";
"call_incoming_voice_prompt" = "Appel vocal entrant de %@";
"call_incoming_video_prompt" = "Appel vidéo entrant de %@";
// No VoIP support
"no_voip_title" = "Appel entrant";
@ -400,38 +402,62 @@
// Crash report
"google_analytics_use_prompt" = "Souhaitez-vous aider à améliorer %@ en envoyant automatiquement des rapports d'erreur et des statistiques d'utilisation ?";
// Crypto
"e2e_enabling_on_app_update" = "Riot supporte maintenant le chiffrement de bout en bout mais vous devez vous identifier à nouveau pour l'activer.\n\nVous pouvez le faire maintenant ou depuis les paramètres de l'application.";
"e2e_need_log_in_again" = "Vous devez vous reconnecter pour générer les clés de chiffrement de bout en bout pour cet appareil et les envoyer vers votre homeserver.\nIl s'agit d'un défaut exceptionnel ; désolé pour le désagrément.";
"e2e_enabling_on_app_update" = "Riot prend désormais en charge le chiffrement de bout en bout, mais vous devez vous reconnecter pour l'activer.\n\nVous pouvez le faire maintenant ou plus tard à partir des paramètres de l'application.";
"e2e_need_log_in_again" = "Vous devez vous reconnecter pour générer les clés de chiffrement de bout en bout pour cet appareil et envoyer la clé publique vers votre serveur d'accueil.\nIl s'agit d'une erreur exceptionnelle. Veuillez nous excuser pour ce désagrément.";
// Bug report
"bug_report_title" = "Rapport d'erreur";
"bug_report_description" = "Merci de décrire l'erreur. Qu'avez-vous fait ? Quel était le comportement attendu ? Que s'est-il passé ?";
"bug_report_description" = "Veuillez décrire l'erreur. Qu'avez-vous fait ? Quel était le comportement attendu ? Que s'est-il réellement passé ?";
"bug_crash_report_title" = "Rapport d'erreur";
"bug_crash_report_description" = "Merci de décrire ce que vous faisiez avant l'arrêt de l'application :";
"bug_report_logs_description" = "Afin de diagnostiquer les problèmes, les traces de ce client seront envoyés avec le rapport d'erreur. Si vous préférez envoyer uniquement le texte ci-dessus, merci de décocher :";
"bug_report_send_logs" = "Envoyer les traces";
"bug_report_logs_description" = "Afin de diagnostiquer les problèmes, les journaux de ce client seront envoyés avec le rapport d'erreur. Si vous préférez envoyer uniquement le texte ci-dessus, veuillez décocher la case :";
"bug_report_send_logs" = "Envoyer les journaux";
"bug_report_send_screenshot" = "Envoyer une capture d'écran";
"bug_report_progress_zipping" = "Collecte des traces";
"bug_report_progress_zipping" = "Collecte des journaux";
"bug_report_progress_uploading" = "Envoi du rapport";
"bug_report_send" = "Envoyer";
"auth_email_in_use" = "Cette adresse e-mail est déjà utilisée";
"auth_phone_in_use" = "Ce numéro de téléphone est déjà utilisé";
"auth_email_not_found" = "Échec lors de l'envoi de l'e-mail : Cette adresse e-mail n'a pas pu être trouvée";
"auth_email_not_found" = "Échec de l'envoi de l'e-mail : Cette adresse e-mail n'a pas pu être trouvée";
"settings_ui_language" = "Langue";
"settings_ui_light_theme" = "Thème clair";
"settings_ui_dark_theme" = "Thème sombre";
"settings_ui_theme" = "Thème";
"settings_ui_theme_auto" = "Auto";
"settings_ui_theme_light" = "Clair";
"settings_ui_theme_dark" = "Sombre";
"settings_ui_theme_picker_title" = "Selectionnez un thème";
"settings_ui_theme_picker_message" = "\"Auto\" utilise le paramètre \"Inverser les couleurs\" de votre appareil";
"collapse" = "réduire";
"auth_untrusted_id_server" = "Le serveur d'identité n'est pas fiable";
"settings_user_interface" = "INTERFACE UTILISATEUR";
// Events formatter
"event_formatter_member_updates" = "%tu changements dans les membres";
"auth_home_server_placeholder" = "URL (e.g. https://matrix.org)";
"auth_identity_server_placeholder" = "URL (e.g. https://matrix.org)";
"room_ongoing_conference_call_with_close" = "Conférence en cours. Rejoindre en %@ ou %@. %@.";
"room_ongoing_conference_call_close" = "Clore";
"room_conference_call_no_power" = "Permissions requises pour gérer la conférence dans ce salon";
"settings_labs_create_conference_with_jitsi" = "Créer les conférences avec jitsi";
"event_formatter_member_updates" = "%tu modifications dans les membres";
"auth_home_server_placeholder" = "URL (par ex. https://matrix.org)";
"auth_identity_server_placeholder" = "URL (par ex. https://matrix.org)";
"room_ongoing_conference_call_with_close" = "Téléconférence en cours. Rejoindre en %@ ou %@. %@.";
"room_ongoing_conference_call_close" = "Fermer";
"room_conference_call_no_power" = "Permissions requises pour gérer la téléconférence dans ce salon";
"settings_labs_create_conference_with_jitsi" = "Créer les téléconférences avec jitsi";
"call_already_displayed" = "Il y a déjà un appel en cours.";
"call_jitsi_error" = "Impossible de joindre la conférence.";
"call_jitsi_error" = "Impossible de rejoindre la téléconférence.";
// Widget
"widget_no_power_to_manage" = "Permissions requises pour gérer les widgets dans ce salon";
"widget_creation_failure" = "Impossible de créer la widget";
"widget_creation_failure" = "Échec de la création du widget";
"send_to" = "Envoyer à %@";
"sending" = "Envoi";
"call_incoming_voice" = "Appel entrant...";
"call_incoming_video" = "Appel vidéo entrant...";
"widget_integration_must_be_in_room" = "Vous n'êtes pas dans ce salon.";
"widget_integration_no_permission_in_room" = "Vous navez pas la permission de faire cela dans ce salon.";
"widget_integration_room_not_visible" = "Le salon %@ n'est pas visible.";
"auth_share_extension_prompt" = "Se connecter dans l'application principale pour partager du contenu";
"room_event_failed_to_send" = "Échec de l'envoi";
"settings_labs_matrix_apps" = "Applications Matrix";
"event_formatter_jitsi_widget_added" = "Téléconférence en Voix sur IP ajoutée par %@";
"event_formatter_jitsi_widget_removed" = "Téléconférence en Voix sur IP supprimée par %@";
// Widget Integration Manager
"widget_integration_need_to_be_able_to_invite" = "Vous devez être capable dinviter des utilisateurs pour faire ça.";
"widget_integration_unable_to_create" = "Impossible de créer le widget.";
"widget_integration_failed_to_send_request" = "Échec de l'envoi de la requête.";
"widget_integration_room_not_recognised" = "Ce salon n'est pas reconnu.";
"widget_integration_positive_power_level" = "Le rang doit être un entier positif.";
"widget_integration_missing_room_id" = "Absence du room_id dans la requête.";
"widget_integration_missing_user_id" = "Absence du user_id dans la requête.";

View file

@ -440,11 +440,20 @@
"contacts_user_directory_offline_section" = "GEBRUIKERSADRESBOEK (offline)";
"settings_user_interface" = "GEBRUIKERSINTERFACE";
"settings_ui_language" = "Taal";
"settings_ui_light_theme" = "Lichte thema";
"settings_ui_dark_theme" = "Donkere thema";
// Read Receipts
"read_receipts_list" = "Leesbewijzen Lijst";
"receipt_status_read" = "Lees: ";
// Events formatter
"event_formatter_member_updates" = "%tu lidmaatschap aanpassingen";
"bug_report_send" = "Stuur";
"auth_home_server_placeholder" = "URL (bv. https://matrix.org)";
"auth_identity_server_placeholder" = "URL (bv. https://matrix.org)";
"room_ongoing_conference_call_with_close" = "Lopend vergadergesprek. Neem deel als %@ of %@. %@ het.";
"room_ongoing_conference_call_close" = "Sluiten";
"room_conference_call_no_power" = "Je hebt permissie nodig om het vergadergesprek in deze ruimte te beheren";
"settings_labs_create_conference_with_jitsi" = "Maak vergadergesprekken met jitsi";
"call_already_displayed" = "Er is al een gesprek aan de gang.";
"call_jitsi_error" = "Het is niet gelukt om aan het vergadergesprek deel te nemen.";
// Widget
"widget_no_power_to_manage" = "Je hebt permissie nodig om widgets in deze ruimte te beheren";
"widget_creation_failure" = "Het creëren van de widget is fout gegaan";

View file

@ -0,0 +1,5 @@
// Permissions usage explanations
"NSCameraUsageDescription" = "Камера используется для съемки фотографий и видеороликов, а также для видеозвонков.";
"NSPhotoLibraryUsageDescription" = "Галерея используется для отправки фотографий и видео.";
"NSMicrophoneUsageDescription" = "Микрофон используется при съемке видео и выполнении звонков.";
"NSContactsUsageDescription" = "Контакты используются для поиска пользователей в Riot по электронной почте или номеру телефона.";

View file

@ -41,7 +41,7 @@
/* Incoming unnamed voice conference invite from a specific person */
"VOICE_CONF_FROM_USER" = "Групповой звонок от %@";
/* Incoming unnamed video conference invite from a specific person */
"VIDEO_CONF_FROM_USER" = "Видеоконференция %@";
"VIDEO_CONF_FROM_USER" = "Групповой видеозвонок от %@";
/* Incoming named voice conference invite from a specific person */
"VOICE_CONF_NAMED_FROM_USER" = "Групповой звонок от %@: '%@'";
/* Incoming named video conference invite from a specific person */

View file

@ -262,8 +262,6 @@
"settings_global_settings_info" = "Глобальные настройки уведомлений доступны в вашем %@ веб-клиенте";
"settings_on_denied_notification" = "Уведомления для %@ запрещены, пожалуйста, разрешите их в настройках вашего устройства";
"settings_ui_language" = "Язык";
"settings_ui_light_theme" = "Светлая тема";
"settings_ui_dark_theme" = "Темная тема";
"settings_unignore_user" = "Показать все сообщения от %@?";
"settings_labs_e2e_encryption" = "Сквозное шифрование";
"settings_labs_e2e_encryption_prompt_message" = "Чтобы завершить настройку шифрования, вы должны войти в систему еще раз.";
@ -421,3 +419,37 @@
"settings_contacts_phonebook_country" = "Страна телефонной книги";
"no_voip" = "%@ вызывает вас, но %@ пока не поддерживает вызовы.\nМожно пропустить это уведомление и ответить на звонок с другого устройства, или вы можете отклонить его.";
"room_participants_remove_third_party_invite_msg" = "Удалить приглашение стороннего сервера невозможно, пока не описан API";
"auth_home_server_placeholder" = "URL (например https://matrix.org)";
"auth_identity_server_placeholder" = "URL (например https://matrix.org)";
"room_ongoing_conference_call_with_close" = "Текущий групповой звонок. Войдите как %@ или %@. %@.";
"room_ongoing_conference_call_close" = "Закрыть";
"room_conference_call_no_power" = "Вам нужно разрешение на управление конференцией в этой комнате";
"room_preview_unlinked_email_warning" = "Это приглашение было отправлено %@, и оно не связано с этой учетной записью. Возможно, вы пожелаете войти в систему с другой учетной записью или добавить это сообщение к вашей учетной записи.";
"settings_labs_create_conference_with_jitsi" = "Создать групповой вызов с jitsi";
"call_already_displayed" = "Вызов уже установлен.";
"call_jitsi_error" = "Не удалось присоединиться к групповому вызову.";
// Widget
"widget_no_power_to_manage" = "Вам нужно разрешение на управление виджетами в этой комнате";
"widget_creation_failure" = "Не удалось создать виджет";
"send_to" = "Отправить %@";
"sending" = "Отправка";
"auth_share_extension_prompt" = "Войти в основное приложение для совместного использования контента";
"room_event_failed_to_send" = "Не удалось отправить";
"settings_labs_matrix_apps" = "Приложения Matrix";
"room_details_direct_chat" = "Прямой чат";
"room_details_fail_to_update_room_direct" = "Не удается обновить прямой флаг этой комнаты";
"event_formatter_jitsi_widget_added" = "Конференция добавлена %@";
"event_formatter_jitsi_widget_removed" = "Конференция удалена %@";
"call_incoming_voice" = "Входящий звонок...";
"call_incoming_video" = "Входящий видеозвонок...";
// Widget Integration Manager
"widget_integration_need_to_be_able_to_invite" = "Вам нужно иметь возможность приглашать пользователей, чтобы сделать это.";
"widget_integration_unable_to_create" = "Не удалось создать виджет.";
"widget_integration_failed_to_send_request" = "Не удалось отправить запрос.";
"widget_integration_room_not_recognised" = "Эта комната не распознана.";
"widget_integration_positive_power_level" = "Уровень доступа должен быть положительным целым числом.";
"widget_integration_must_be_in_room" = "Вас нет в этой комнате.";
"widget_integration_no_permission_in_room" = "У вас нет полномочий в этой комнате.";
"widget_integration_missing_room_id" = "Отсутствует room_id в запросе.";
"widget_integration_missing_user_id" = "Отсутствует user_id в запросе.";
"widget_integration_room_not_visible" = "Комната %@ не видна.";

View file

@ -421,3 +421,9 @@
"settings_ui_dark_theme" = "暗色主题";
// Events formatter
"event_formatter_member_updates" = "%tu 的成员身份变化";
"auth_home_server_placeholder" = "URL例如 https://matrix.org";
"auth_identity_server_placeholder" = "URL例如 https://matrix.org";
"contacts_user_directory_section" = "用户目录";
"contacts_user_directory_offline_section" = "用户目录(离线)";
"room_ongoing_conference_call_with_close" = "收到会议通话。以 %@ 或 %@.%@ 加入。";
"room_ongoing_conference_call_close" = "关闭";

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

@ -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.5</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>0.5.3</string>
<string>0.5.5</string>
<key>ITSAppUsesNonExemptEncryption</key>
<true/>
<key>ITSEncryptionExportComplianceCode</key>

View file

@ -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

@ -46,25 +46,52 @@
{
NSString *displayText;
// Prepare the display name of the sender
NSString *senderDisplayName = roomState ? [self senderDisplayNameForEvent:event withRoomState:roomState] : event.sender;
Widget *widget = [[Widget alloc] initWithWidgetEvent:event inMatrixSession:mxSession];
if (widget)
{
// Prepare the display name of the sender
NSString *senderDisplayName = roomState ? [self senderDisplayNameForEvent:event withRoomState:roomState] : event.sender;
if ([event.content[@"type"] isEqualToString:kWidgetTypeJitsi])
{
// This is an alive jitsi widget
displayText = [NSString stringWithFormat:NSLocalizedStringFromTable(@"event_formatter_jitsi_widget_added", @"Vector", nil), senderDisplayName];
}
else if (event.content.count == 0)
{
// This is a closed widget
// Check if it corresponds to a jitsi widget by looking at other state events for
// this jitsi widget (widget id = event.stateKey).
for (MXEvent *widgetStateEvent in [roomState stateEventsWithType:kWidgetEventTypeString])
if (widget.isActive)
{
if ([widgetStateEvent.stateKey isEqualToString:event.stateKey] && [widgetStateEvent.content[@"type"] isEqualToString:kWidgetTypeJitsi])
if ([widget.type isEqualToString:kWidgetTypeJitsi])
{
displayText = [NSString stringWithFormat:NSLocalizedStringFromTable(@"event_formatter_jitsi_widget_removed", @"Vector", nil), senderDisplayName];
break;
// This is an alive jitsi widget
displayText = [NSString stringWithFormat:NSLocalizedStringFromTable(@"event_formatter_jitsi_widget_added", @"Vector", nil), senderDisplayName];
}
else
{
displayText = [NSString stringWithFormat:NSLocalizedStringFromTable(@"event_formatter_widget_added", @"Vector", nil),
widget.name ? widget.name : widget.type,
senderDisplayName];
}
}
else
{
// This is a closed widget
// Check if it corresponds to a jitsi widget by looking at other state events for
// this jitsi widget (widget id = event.stateKey).
for (MXEvent *widgetStateEvent in [roomState stateEventsWithType:kWidgetEventTypeString])
{
if ([widgetStateEvent.stateKey isEqualToString:widget.widgetId])
{
Widget *activeWidget = [[Widget alloc] initWithWidgetEvent:widgetStateEvent inMatrixSession:mxSession];
if (activeWidget.isActive)
{
if ([activeWidget.type isEqualToString:kWidgetTypeJitsi])
{
// This was a jitsi widget
displayText = [NSString stringWithFormat:NSLocalizedStringFromTable(@"event_formatter_jitsi_widget_removed", @"Vector", nil), senderDisplayName];
}
else
{
displayText = [NSString stringWithFormat:NSLocalizedStringFromTable(@"event_formatter_widget_removed", @"Vector", nil),
activeWidget.name ? activeWidget.name : activeWidget.type,
senderDisplayName];
}
break;
}
}
}
}
}

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

@ -112,8 +112,10 @@ UIColor *kRiotDesignSearchBarTintColor = nil;
// Observe user interface theme change.
[[NSUserDefaults standardUserDefaults] addObserver:[RiotDesignValues sharedInstance] forKeyPath:@"userInterfaceTheme" options:0 context:nil];
[[RiotDesignValues sharedInstance] userInterfaceThemeDidChange];
}
// Observe "Invert Colours" settings changes (available since iOS 11)
[[NSNotificationCenter defaultCenter] addObserver:[RiotDesignValues sharedInstance] selector:@selector(accessibilityInvertColorsStatusDidChange) name:UIAccessibilityInvertColorsStatusDidChangeNotification object:nil];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
@ -123,10 +125,25 @@ UIColor *kRiotDesignSearchBarTintColor = nil;
}
}
- (void)accessibilityInvertColorsStatusDidChange
{
// Refresh the theme only for "auto"
NSString *theme = [[NSUserDefaults standardUserDefaults] stringForKey:@"userInterfaceTheme"];
if (!theme || [theme isEqualToString:@"auto"])
{
[self userInterfaceThemeDidChange];
}
}
- (void)userInterfaceThemeDidChange
{
// Retrieve the current selected theme ("light" if none).
// Retrieve the current selected theme ("light" if none. "auto" is used as default from iOS 11).
NSString *theme = [[NSUserDefaults standardUserDefaults] stringForKey:@"userInterfaceTheme"];
if (!theme || [theme isEqualToString:@"auto"])
{
theme = UIAccessibilityIsInvertColorsEnabled() ? @"dark" : @"light";
}
// Currently only 2 themes is supported
if ([theme isEqualToString:@"dark"])

View file

@ -41,22 +41,25 @@
MXJSONModelSetDictionary(_data, widgetEvent.content[@"data"]);
// Format the url string with user data
_url = [_url stringByReplacingOccurrencesOfString:@"$matrix_user_id" withString:mxSession.myUser.userId];
_url = [_url stringByReplacingOccurrencesOfString:@"$matrix_display_name"
withString:mxSession.myUser.displayname ? mxSession.myUser.displayname : mxSession.myUser.userId];
_url = [_url stringByReplacingOccurrencesOfString:@"$matrix_avatar_url"
withString:mxSession.myUser.avatarUrl ? mxSession.myUser.avatarUrl : @""];
if (_url)
{
_url = [_url stringByReplacingOccurrencesOfString:@"$matrix_user_id" withString:mxSession.myUser.userId];
_url = [_url stringByReplacingOccurrencesOfString:@"$matrix_display_name"
withString:mxSession.myUser.displayname ? mxSession.myUser.displayname : mxSession.myUser.userId];
_url = [_url stringByReplacingOccurrencesOfString:@"$matrix_avatar_url"
withString:mxSession.myUser.avatarUrl ? mxSession.myUser.avatarUrl : @""];
// And their scalar token
NSString *scalarToken = [[WidgetManager sharedManager] scalarTokenForMXSession:mxSession];
if (scalarToken)
{
_url = [_url stringByAppendingString:[NSString stringWithFormat:@"&scalar_token=%@", scalarToken]];
}
else
{
// Some widget can live without scalar token (ex: Jitsi widget)
NSLog(@"[Widget] Note: There is no scalar token for %@", self);
// And their scalar token
NSString *scalarToken = [[WidgetManager sharedManager] scalarTokenForMXSession:mxSession];
if (scalarToken)
{
_url = [_url stringByAppendingString:[NSString stringWithFormat:@"&scalar_token=%@", scalarToken]];
}
else
{
// Some widget can live without scalar token (ex: Jitsi widget)
NSLog(@"[Widget] Note: There is no scalar token for %@", self);
}
}
}

View file

@ -72,12 +72,20 @@ WidgetManagerErrorCode;
/**
List all active widgets of a given type in a room.
@param widgetType the types of widget to search.
@param widgetTypes the types of widget to search. Nil means all types.
@param room the room to check.
@return a list of widgets.
*/
- (NSArray<Widget*> *)widgetsOfTypes:(NSArray<NSString*>*)widgetTypes inRoom:(MXRoom*)room;
/**
List all active widgets of a given type in a room, excluding some types.
@param notWidgetTypes the types of widget to not consider. Nil means all types.
@param room the room to check.
@return a list of widgets.
*/
- (NSArray<Widget*> *)widgetsNotOfTypes:(NSArray<NSString*>*)notWidgetTypes inRoom:(MXRoom*)room;
/**
Add a modular widget to a room.

View file

@ -87,7 +87,17 @@ NSString *const WidgetManagerErrorDomain = @"WidgetManagerErrorDomain";
return [self widgetsOfTypes:nil inRoom:room];
}
- (NSArray<Widget *> *)widgetsOfTypes:(NSArray<NSString *> *)widgetTypes inRoom:(MXRoom *)room
- (NSArray<Widget*> *)widgetsOfTypes:(NSArray<NSString*>*)widgetTypes inRoom:(MXRoom*)room;
{
return [self widgetsOfTypes:widgetTypes butNotTypesOf:nil inRoom:room];
}
- (NSArray<Widget*> *)widgetsNotOfTypes:(NSArray<NSString*>*)notWidgetTypes inRoom:(MXRoom*)room
{
return [self widgetsOfTypes:nil butNotTypesOf:notWidgetTypes inRoom:room];
}
- (NSArray<Widget*> *)widgetsOfTypes:(NSArray<NSString*>*)widgetTypes butNotTypesOf:(NSArray<NSString*>*)notWidgetTypes inRoom:(MXRoom*)room;
{
// Widget id -> widget
NSMutableDictionary <NSString*, Widget *> *widgets = [NSMutableDictionary dictionary];
@ -118,14 +128,21 @@ NSString *const WidgetManagerErrorDomain = @"WidgetManagerErrorDomain";
for (MXEvent *widgetEvent in widgetEvents)
{
// Filter widget types if required
if (widgetTypes)
if (widgetTypes || notWidgetTypes)
{
NSString *widgetType;
MXJSONModelSetString(widgetType, widgetEvent.content[@"type"]);
if (widgetType && NSNotFound == [widgetTypes indexOfObject:widgetType])
if (widgetType)
{
continue;
if (widgetTypes && NSNotFound == [widgetTypes indexOfObject:widgetType])
{
continue;
}
if (notWidgetTypes && NSNotFound != [notWidgetTypes indexOfObject:widgetType])
{
continue;
}
}
}

View file

@ -35,7 +35,7 @@
#define TABLEVIEW_SECTION_HEADER_HEIGHT 28
#define TABLEVIEW_SECTION_HEADER_HEIGHT_WHEN_HIDDEN 0.01f
@interface ContactDetailsViewController ()
@interface ContactDetailsViewController () <RoomMemberTitleViewDelegate>
{
RoomMemberTitleView* contactTitleView;
MXKImageView *contactAvatar;
@ -132,19 +132,62 @@
actionsArray = [[NSMutableArray alloc] init];
directChatsArray = [[NSMutableArray alloc] init];
contactTitleView = [RoomMemberTitleView roomMemberTitleView];
contactTitleView.delegate = self;
contactAvatar = contactTitleView.memberAvatar;
contactAvatar.contentMode = UIViewContentModeScaleAspectFill;
contactAvatar.defaultBackgroundColor = [UIColor clearColor];
if (@available(iOS 11.0, *))
{
// Define directly the navigation titleView with the custom title view instance. Do not use anymore a container.
self.navigationItem.titleView = contactTitleView;
}
else
{
self.navigationItem.titleView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 600, 40)];
// Add the title view and define edge constraints
contactTitleView.translatesAutoresizingMaskIntoConstraints = NO;
[self.navigationItem.titleView addSubview:contactTitleView];
NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:contactTitleView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.navigationItem.titleView
attribute:NSLayoutAttributeTop
multiplier:1.0f
constant:0.0f];
NSLayoutConstraint *bottomConstraint = [NSLayoutConstraint constraintWithItem:contactTitleView
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self.navigationItem.titleView
attribute:NSLayoutAttributeBottom
multiplier:1.0f
constant:0.0f];
NSLayoutConstraint *leadingConstraint = [NSLayoutConstraint constraintWithItem:contactTitleView
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:self.navigationItem.titleView
attribute:NSLayoutAttributeLeading
multiplier:1.0f
constant:0.0f];
NSLayoutConstraint *trailingConstraint = [NSLayoutConstraint constraintWithItem:contactTitleView
attribute:NSLayoutAttributeTrailing
relatedBy:NSLayoutRelationEqual
toItem:self.navigationItem.titleView
attribute:NSLayoutAttributeTrailing
multiplier:1.0f
constant:0.0f];
[NSLayoutConstraint activateConstraints:@[topConstraint, bottomConstraint, leadingConstraint, trailingConstraint]];
}
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapGesture:)];
[tap setNumberOfTouchesRequired:1];
[tap setNumberOfTapsRequired:1];
[tap setDelegate:self];
[self.contactNameLabelMask addGestureRecognizer:tap];
self.contactNameLabelMask.userInteractionEnabled = YES;
self.navigationItem.titleView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 600, 40)];
contactTitleView = [RoomMemberTitleView roomMemberTitleView];
contactAvatar = contactTitleView.memberAvatar;
contactAvatar.contentMode = UIViewContentModeScaleAspectFill;
contactAvatar.defaultBackgroundColor = [UIColor clearColor];
// Add tap to show the contact avatar in fullscreen
tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapGesture:)];
@ -162,40 +205,6 @@
[tap setDelegate:self];
[self.contactAvatarMask addGestureRecognizer:tap];
self.contactAvatarMask.userInteractionEnabled = YES;
// Add the title view and define edge constraints
contactTitleView.translatesAutoresizingMaskIntoConstraints = NO;
[self.navigationItem.titleView addSubview:contactTitleView];
NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:contactTitleView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.navigationItem.titleView
attribute:NSLayoutAttributeTop
multiplier:1.0f
constant:0.0f];
NSLayoutConstraint *bottomConstraint = [NSLayoutConstraint constraintWithItem:contactTitleView
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self.navigationItem.titleView
attribute:NSLayoutAttributeBottom
multiplier:1.0f
constant:0.0f];
NSLayoutConstraint *leadingConstraint = [NSLayoutConstraint constraintWithItem:contactTitleView
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:self.navigationItem.titleView
attribute:NSLayoutAttributeLeading
multiplier:1.0f
constant:0.0f];
NSLayoutConstraint *trailingConstraint = [NSLayoutConstraint constraintWithItem:contactTitleView
attribute:NSLayoutAttributeTrailing
relatedBy:NSLayoutRelationEqual
toItem:self.navigationItem.titleView
attribute:NSLayoutAttributeTrailing
multiplier:1.0f
constant:0.0f];
[NSLayoutConstraint activateConstraints:@[topConstraint, bottomConstraint, leadingConstraint, trailingConstraint]];
// Register collection view cell class
[self.tableView registerClass:TableViewCellWithButton.class forCellReuseIdentifier:[TableViewCellWithButton defaultReuseIdentifier]];
@ -354,7 +363,8 @@
{
[super viewDidLayoutSubviews];
if (contactTitleView)
// Check whether the title view has been created and rendered.
if (contactTitleView && contactTitleView.superview)
{
// Adjust the header height by taking into account the actual position of the member avatar in title view
// This position depends automatically on the screen orientation.
@ -1177,4 +1187,11 @@
}
}
#pragma mark - RoomMemberTitleViewDelegate
- (void)roomMemberTitleViewDidLayoutSubview:(RoomMemberTitleView*)titleView
{
[self viewDidLayoutSubviews];
}
@end

View file

@ -163,7 +163,7 @@
// Observe kAppDelegateDidTapStatusBarNotification.
kAppDelegateDidTapStatusBarNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kAppDelegateDidTapStatusBarNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
[self.contactsTableView setContentOffset:CGPointMake(-self.contactsTableView.contentInset.left, -self.contactsTableView.contentInset.top) animated:YES];
[self.contactsTableView setContentOffset:CGPointMake(-self.contactsTableView.mxk_adjustedContentInset.left, -self.contactsTableView.mxk_adjustedContentInset.top) animated:YES];
}];
@ -285,7 +285,7 @@
- (void)scrollToTop:(BOOL)animated
{
// Scroll to the top
[self.contactsTableView setContentOffset:CGPointMake(-self.contactsTableView.contentInset.left, -self.contactsTableView.contentInset.top) animated:animated];
[self.contactsTableView setContentOffset:CGPointMake(-self.contactsTableView.mxk_adjustedContentInset.left, -self.contactsTableView.mxk_adjustedContentInset.top) animated:animated];
}
#pragma mark - UITableView delegate

View file

@ -153,7 +153,7 @@
// Observe kAppDelegateDidTapStatusBarNotificationObserver.
kAppDelegateDidTapStatusBarNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kAppDelegateDidTapStatusBarNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
[self.tableView setContentOffset:CGPointMake(-self.tableView.contentInset.left, -self.tableView.contentInset.top) animated:YES];
[self.tableView setContentOffset:CGPointMake(-self.tableView.mxk_adjustedContentInset.left, -self.tableView.mxk_adjustedContentInset.top) animated:YES];
}];

View file

@ -115,7 +115,7 @@
// Observe kAppDelegateDidTapStatusBarNotificationObserver.
kAppDelegateDidTapStatusBarNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kAppDelegateDidTapStatusBarNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
[self.tableView setContentOffset:CGPointMake(-self.tableView.contentInset.left, -self.tableView.contentInset.top) animated:YES];
[self.tableView setContentOffset:CGPointMake(-self.tableView.mxk_adjustedContentInset.left, -self.tableView.mxk_adjustedContentInset.top) animated:YES];
}];

View file

@ -1000,6 +1000,12 @@ static void *RecordingContext = &RecordingContext;
NSLog(@"[MediaPickerVC] Attemping to setup AVCapture when it is already started!");
return;
}
if (!cameraQueue)
{
NSLog(@"[MediaPickerVC] Attemping to setup AVCapture when it is being destroyed!");
return;
}
isCaptureSessionSetupInProgress = YES;
[self.cameraActivityIndicator startAnimating];
@ -1192,6 +1198,12 @@ static void *RecordingContext = &RecordingContext;
- (void)tearDownAVCapture
{
if (!cameraQueue)
{
NSLog(@"[MediaPickerVC] Attemping to tear down AVCapture when it is being destroyed!");
return;
}
dispatch_sync(cameraQueue, ^{
frontCameraInput = nil;
backCameraInput = nil;

View file

@ -656,7 +656,7 @@
}
// Look for the lowest section index visible in the bottom sticky headers.
CGFloat maxVisiblePosY = self.recentsTableView.contentOffset.y + self.recentsTableView.frame.size.height - self.recentsTableView.contentInset.bottom;
CGFloat maxVisiblePosY = self.recentsTableView.contentOffset.y + self.recentsTableView.frame.size.height - self.recentsTableView.mxk_adjustedContentInset.bottom;
UIView *lastDisplayedSectionHeader = displayedSectionHeaders.lastObject;
for (UIView *header in _stickyHeadersBottomContainer.subviews)
@ -1252,7 +1252,7 @@
{
if (!self.recentsSearchBar.isHidden)
{
if (!self.recentsSearchBar.text.length && (scrollView.contentOffset.y + scrollView.contentInset.top > self.recentsSearchBar.frame.size.height))
if (!self.recentsSearchBar.text.length && (scrollView.contentOffset.y + scrollView.mxk_adjustedContentInset.top > self.recentsSearchBar.frame.size.height))
{
// Hide the search bar
[self hideSearchBar:YES];
@ -1770,7 +1770,7 @@
- (void)scrollToTop:(BOOL)animated
{
[self.recentsTableView setContentOffset:CGPointMake(-self.recentsTableView.contentInset.left, -self.recentsTableView.contentInset.top) animated:animated];
[self.recentsTableView setContentOffset:CGPointMake(-self.recentsTableView.mxk_adjustedContentInset.left, -self.recentsTableView.mxk_adjustedContentInset.top) animated:animated];
}
- (void)scrollToTheTopTheNextRoomWithMissedNotificationsInSection:(NSInteger)section

View file

@ -118,7 +118,7 @@
// Observe kAppDelegateDidTapStatusBarNotificationObserver.
kAppDelegateDidTapStatusBarNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kAppDelegateDidTapStatusBarNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
[self.searchTableView setContentOffset:CGPointMake(-self.searchTableView.contentInset.left, -self.searchTableView.contentInset.top) animated:YES];
[self.searchTableView setContentOffset:CGPointMake(-self.searchTableView.mxk_adjustedContentInset.left, -self.searchTableView.mxk_adjustedContentInset.top) animated:YES];
}];
}

View file

@ -33,7 +33,7 @@
#define TABLEVIEW_SECTION_HEADER_HEIGHT 28
#define TABLEVIEW_SECTION_HEADER_HEIGHT_WHEN_HIDDEN 0.01f
@interface RoomMemberDetailsViewController ()
@interface RoomMemberDetailsViewController () <RoomMemberTitleViewDelegate>
{
RoomMemberTitleView* memberTitleView;
@ -118,6 +118,58 @@
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
memberTitleView = [RoomMemberTitleView roomMemberTitleView];
memberTitleView.delegate = self;
if (@available(iOS 11.0, *))
{
// Define directly the navigation titleView with the custom title view instance. Do not use anymore a container.
self.navigationItem.titleView = memberTitleView;
}
else
{
self.navigationItem.titleView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 600, 40)];
// Add the title view and define edge constraints
memberTitleView.translatesAutoresizingMaskIntoConstraints = NO;
[self.navigationItem.titleView addSubview:memberTitleView];
NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:memberTitleView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.navigationItem.titleView
attribute:NSLayoutAttributeTop
multiplier:1.0f
constant:0.0f];
NSLayoutConstraint *bottomConstraint = [NSLayoutConstraint constraintWithItem:memberTitleView
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self.navigationItem.titleView
attribute:NSLayoutAttributeBottom
multiplier:1.0f
constant:0.0f];
NSLayoutConstraint *leadingConstraint = [NSLayoutConstraint constraintWithItem:memberTitleView
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:self.navigationItem.titleView
attribute:NSLayoutAttributeLeading
multiplier:1.0f
constant:0.0f];
NSLayoutConstraint *trailingConstraint = [NSLayoutConstraint constraintWithItem:memberTitleView
attribute:NSLayoutAttributeTrailing
relatedBy:NSLayoutRelationEqual
toItem:self.navigationItem.titleView
attribute:NSLayoutAttributeTrailing
multiplier:1.0f
constant:0.0f];
[NSLayoutConstraint activateConstraints:@[topConstraint, bottomConstraint, leadingConstraint, trailingConstraint]];
}
// Handle the member avatar at the view controller level.
self.memberThumbnail = memberTitleView.memberAvatar;
// Add tap gesture on member's name
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapGesture:)];
[tap setNumberOfTouchesRequired:1];
[tap setNumberOfTapsRequired:1];
@ -125,11 +177,6 @@
[self.roomMemberNameLabelMask addGestureRecognizer:tap];
self.roomMemberNameLabelMask.userInteractionEnabled = YES;
self.navigationItem.titleView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 600, 40)];
memberTitleView = [RoomMemberTitleView roomMemberTitleView];
self.memberThumbnail = memberTitleView.memberAvatar;
// Add tap to show the room member avatar in fullscreen
tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapGesture:)];
[tap setNumberOfTouchesRequired:1];
@ -146,40 +193,6 @@
[tap setDelegate:self];
[self.roomMemberAvatarMask addGestureRecognizer:tap];
self.roomMemberAvatarMask.userInteractionEnabled = YES;
// Add the title view and define edge constraints
memberTitleView.translatesAutoresizingMaskIntoConstraints = NO;
[self.navigationItem.titleView addSubview:memberTitleView];
NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:memberTitleView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.navigationItem.titleView
attribute:NSLayoutAttributeTop
multiplier:1.0f
constant:0.0f];
NSLayoutConstraint *bottomConstraint = [NSLayoutConstraint constraintWithItem:memberTitleView
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self.navigationItem.titleView
attribute:NSLayoutAttributeBottom
multiplier:1.0f
constant:0.0f];
NSLayoutConstraint *leadingConstraint = [NSLayoutConstraint constraintWithItem:memberTitleView
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:self.navigationItem.titleView
attribute:NSLayoutAttributeLeading
multiplier:1.0f
constant:0.0f];
NSLayoutConstraint *trailingConstraint = [NSLayoutConstraint constraintWithItem:memberTitleView
attribute:NSLayoutAttributeTrailing
relatedBy:NSLayoutRelationEqual
toItem:self.navigationItem.titleView
attribute:NSLayoutAttributeTrailing
multiplier:1.0f
constant:0.0f];
[NSLayoutConstraint activateConstraints:@[topConstraint, bottomConstraint, leadingConstraint, trailingConstraint]];
// Register collection view cell class
[self.tableView registerClass:TableViewCellWithButton.class forCellReuseIdentifier:[TableViewCellWithButton defaultReuseIdentifier]];
@ -323,7 +336,8 @@
}
}
if (memberTitleView)
// Check whether the title view has been created and rendered.
if (memberTitleView && memberTitleView.superview)
{
// Adjust the header height by taking into account the actual position of the member avatar in title view
// This position depends automatically on the screen orientation.
@ -1047,4 +1061,11 @@
}
}
#pragma mark - RoomMemberTitleViewDelegate
- (void)roomMemberTitleViewDidLayoutSubview:(RoomMemberTitleView*)titleView
{
[self viewDidLayoutSubviews];
}
@end

View file

@ -119,7 +119,7 @@
// Observe kAppDelegateDidTapStatusBarNotificationObserver.
kAppDelegateDidTapStatusBarNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kAppDelegateDidTapStatusBarNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
[self.searchTableView setContentOffset:CGPointMake(-self.searchTableView.contentInset.left, -self.searchTableView.contentInset.top) animated:YES];
[self.searchTableView setContentOffset:CGPointMake(-self.searchTableView.mxk_adjustedContentInset.left, -self.searchTableView.mxk_adjustedContentInset.top) animated:YES];
}];
}

View file

@ -278,7 +278,7 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti
// Observe appDelegateDidTapStatusBarNotificationObserver.
appDelegateDidTapStatusBarNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kAppDelegateDidTapStatusBarNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
[self.tableView setContentOffset:CGPointMake(-self.tableView.contentInset.left, -self.tableView.contentInset.top) animated:YES];
[self.tableView setContentOffset:CGPointMake(-self.tableView.mxk_adjustedContentInset.left, -self.tableView.mxk_adjustedContentInset.top) animated:YES];
}];
}

View file

@ -110,7 +110,7 @@
#import "MXRoom+Riot.h"
#import "IntegrationManagerViewController.h"
#import "WidgetViewController.h"
#import "WidgetPickerViewController.h"
@interface RoomViewController ()
{
@ -374,6 +374,14 @@
missedDiscussionsBarButtonCustomView.backgroundColor = [UIColor clearColor];
missedDiscussionsBarButtonCustomView.clipsToBounds = NO;
NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintWithItem:missedDiscussionsBarButtonCustomView
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:21];
missedDiscussionsBadgeLabelBgView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 21, 21)];
[missedDiscussionsBadgeLabelBgView.layer setCornerRadius:10];
@ -399,7 +407,7 @@
multiplier:1.0
constant:0];
[NSLayoutConstraint activateConstraints:@[centerXConstraint, centerYConstraint]];
[NSLayoutConstraint activateConstraints:@[heightConstraint, centerXConstraint, centerYConstraint]];
// Set up the room title view according to the data source (if any)
[self refreshRoomTitle];
@ -491,7 +499,7 @@
// Observe kAppDelegateDidTapStatusBarNotification.
kAppDelegateDidTapStatusBarNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kAppDelegateDidTapStatusBarNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
[self.bubblesTableView setContentOffset:CGPointMake(-self.bubblesTableView.contentInset.left, -self.bubblesTableView.contentInset.top) animated:YES];
[self.bubblesTableView setContentOffset:CGPointMake(-self.bubblesTableView.mxk_adjustedContentInset.left, -self.bubblesTableView.mxk_adjustedContentInset.top) animated:YES];
}];
}
@ -683,7 +691,7 @@
CGRect frame = expandedHeader.bottomBorderView.frame;
self.expandedHeaderContainerHeightConstraint.constant = frame.origin.y + frame.size.height;
self.bubblesTableViewTopConstraint.constant = self.expandedHeaderContainerHeightConstraint.constant - self.bubblesTableView.contentInset.top;
self.bubblesTableViewTopConstraint.constant = self.expandedHeaderContainerHeightConstraint.constant - self.bubblesTableView.mxk_adjustedContentInset.top;
self.jumpToLastUnreadBannerContainerTopConstraint.constant = self.expandedHeaderContainerHeightConstraint.constant;
}
// Check whether the preview header is visible
@ -710,12 +718,12 @@
CGRect frame = previewHeader.bottomBorderView.frame;
self.previewHeaderContainerHeightConstraint.constant = frame.origin.y + frame.size.height;
self.bubblesTableViewTopConstraint.constant = self.previewHeaderContainerHeightConstraint.constant - self.bubblesTableView.contentInset.top;
self.bubblesTableViewTopConstraint.constant = self.previewHeaderContainerHeightConstraint.constant - self.bubblesTableView.mxk_adjustedContentInset.top;
self.jumpToLastUnreadBannerContainerTopConstraint.constant = self.previewHeaderContainerHeightConstraint.constant;
}
else
{
self.jumpToLastUnreadBannerContainerTopConstraint.constant = self.bubblesTableView.contentInset.top;
self.jumpToLastUnreadBannerContainerTopConstraint.constant = self.bubblesTableView.mxk_adjustedContentInset.top;
}
[self refreshMissedDiscussionsCount:YES];
@ -1189,13 +1197,31 @@
barButtonItem.enabled = YES;
}
BOOL matrixAppsEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:@"matrixApps"];
if (!matrixAppsEnabled && self.navigationItem.rightBarButtonItems.count == 2)
if (self.navigationItem.rightBarButtonItems.count == 2)
{
// If the setting is disabled, do not show the icon
self.navigationItem.rightBarButtonItems = @[self.navigationItem.rightBarButtonItem];
BOOL matrixAppsEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:@"matrixApps"];
if (!matrixAppsEnabled)
{
// If the setting is disabled, do not show the icon
self.navigationItem.rightBarButtonItems = @[self.navigationItem.rightBarButtonItem];
}
else if (self.widgetsCount)
{
// Show there are widgets by changing the "apps" icon color
// TODO: Design must be reviewed
UIImage *icon = self.navigationItem.rightBarButtonItems[1].image;
icon = [MXKTools paintImage:icon withColor:kRiotColorPinkRed];
icon = [icon imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
self.navigationItem.rightBarButtonItems[1].image = icon;
}
else
{
// Reset original icon
self.navigationItem.rightBarButtonItems[1].image = [UIImage imageNamed:@"apps-icon"];
}
}
// Do not change title view class here if the expanded header is visible.
if (self.expandedHeaderContainer.hidden)
{
@ -1366,8 +1392,8 @@
[UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionCurveEaseIn
animations:^{
self.bubblesTableViewTopConstraint.constant = (isVisible ? self.expandedHeaderContainerHeightConstraint.constant - self.bubblesTableView.contentInset.top : 0);
self.jumpToLastUnreadBannerContainerTopConstraint.constant = (isVisible ? self.expandedHeaderContainerHeightConstraint.constant : self.bubblesTableView.contentInset.top);
self.bubblesTableViewTopConstraint.constant = (isVisible ? self.expandedHeaderContainerHeightConstraint.constant - self.bubblesTableView.mxk_adjustedContentInset.top : 0);
self.jumpToLastUnreadBannerContainerTopConstraint.constant = (isVisible ? self.expandedHeaderContainerHeightConstraint.constant : self.bubblesTableView.mxk_adjustedContentInset.top);
if (roomAvatarView)
{
@ -1482,7 +1508,7 @@
animations:^{
self.bubblesTableViewTopConstraint.constant = 0;
self.jumpToLastUnreadBannerContainerTopConstraint.constant = self.bubblesTableView.contentInset.top;
self.jumpToLastUnreadBannerContainerTopConstraint.constant = self.bubblesTableView.mxk_adjustedContentInset.top;
// Force to render the view
[self forceLayoutRefresh];
@ -1573,7 +1599,7 @@
[UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionCurveEaseIn
animations:^{
self.bubblesTableViewTopConstraint.constant = self.previewHeaderContainerHeightConstraint.constant - self.bubblesTableView.contentInset.top;
self.bubblesTableViewTopConstraint.constant = self.previewHeaderContainerHeightConstraint.constant - self.bubblesTableView.mxk_adjustedContentInset.top;
self.jumpToLastUnreadBannerContainerTopConstraint.constant = self.previewHeaderContainerHeightConstraint.constant;
if (roomAvatarView)
@ -2712,7 +2738,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)
@ -2749,11 +2774,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];
@ -2881,19 +2903,16 @@
// Matrix Apps button
else if (self.navigationItem.rightBarButtonItems.count == 2 && sender == self.navigationItem.rightBarButtonItems[1])
{
// Temporary code to test `WidgetViewController`
// TODO: remove it
// NSArray<Widget *> *widgets = [[WidgetManager sharedManager] widgetsInRoom:self.roomDataSource.room];
// if (widgets.count)
// {
// // Hide back button title
// self.navigationItem.backBarButtonItem =[[UIBarButtonItem alloc] initWithTitle:@"" style:UIBarButtonItemStylePlain target:nil action:nil];
//
// WidgetViewController *widgetVC = [[WidgetViewController alloc] initForWidget:widgets[0]];
// [self.navigationController pushViewController:widgetVC animated:YES];
// }
// else
if (self.widgetsCount)
{
WidgetPickerViewController *widgetPicker = [[WidgetPickerViewController alloc] initForMXSession:self.roomDataSource.mxSession
inRoom:self.roomDataSource.roomId];
[widgetPicker showInViewController:self];
}
else
{
// No widgets -> Directly show the integration manager
IntegrationManagerViewController *modularVC = [[IntegrationManagerViewController alloc] initForMXSession:self.roomDataSource.mxSession
inRoom:self.roomDataSource.roomId
screen:kIntegrationManagerMainScreen
@ -2993,7 +3012,7 @@
// Switch back to the live mode when the user scrolls to the bottom of the non live timeline.
if (!self.roomDataSource.isLive && ![self isRoomPreview])
{
CGFloat contentBottomPosY = self.bubblesTableView.contentOffset.y + self.bubblesTableView.frame.size.height - self.bubblesTableView.contentInset.bottom;
CGFloat contentBottomPosY = self.bubblesTableView.contentOffset.y + self.bubblesTableView.frame.size.height - self.bubblesTableView.mxk_adjustedContentInset.bottom;
if (contentBottomPosY >= self.bubblesTableView.contentSize.height && ![self.roomDataSource.timeline canPaginate:MXTimelineDirectionForwards])
{
[self goBackToLive];
@ -3445,6 +3464,7 @@
// Update the bar
[self refreshActivitiesViewDisplay];
[self refreshRoomInputToolbar];
[self refreshRoomTitle];
}
}];
}
@ -3465,6 +3485,12 @@
[[AppDelegate theDelegate] showErrorAsAlert:error];
}
- (NSUInteger)widgetsCount
{
return [[WidgetManager sharedManager] widgetsNotOfTypes:@[kWidgetTypeJitsi]
inRoom:self.roomDataSource.room].count;
}
#pragma mark - Unreachable Network Handling
- (void)refreshActivitiesViewDisplay
@ -3510,7 +3536,6 @@
} onClosePressed:nil];
}
}
#ifdef USE_JITSI_WIDGET
else if (jitsiWidget)
{
// The room has an active jitsi widget
@ -3580,7 +3605,6 @@
}];
}
}
#endif
else if ([self checkUnsentMessages] == NO)
{
// Show "scroll to bottom" icon when the most recent message is not visible,
@ -3700,15 +3724,6 @@
if (missedCount)
{
// Consider the main navigation controller if the current view controller is embedded inside a split view controller.
UINavigationController *mainNavigationController = self.navigationController;
if (self.splitViewController.isCollapsed && self.splitViewController.viewControllers.count)
{
mainNavigationController = self.splitViewController.viewControllers.firstObject;
}
UINavigationItem *backItem = mainNavigationController.navigationBar.backItem;
UIBarButtonItem *backButton = backItem.backBarButtonItem;
// Refresh missed discussions count label
if (missedCount > 99)
{
@ -3724,25 +3739,33 @@
// Update the label background view frame
CGRect frame = missedDiscussionsBadgeLabelBgView.frame;
frame.size.width = round(missedDiscussionsBadgeLabel.frame.size.width + 18);
if (backButton && !backButton.title.length)
if ([GBDeviceInfo deviceInfo].osVersion.major < 11)
{
// Shift the badge on the left to be close the back icon
frame.origin.x = ([GBDeviceInfo deviceInfo].displayInfo.display > GBDeviceDisplay4Inch ? -35 : -25);
}
else
{
frame.origin.x = 0;
// Consider the main navigation controller if the current view controller is embedded inside a split view controller.
UINavigationController *mainNavigationController = self.navigationController;
if (self.splitViewController.isCollapsed && self.splitViewController.viewControllers.count)
{
mainNavigationController = self.splitViewController.viewControllers.firstObject;
}
UINavigationItem *backItem = mainNavigationController.navigationBar.backItem;
UIBarButtonItem *backButton = backItem.backBarButtonItem;
if (backButton && !backButton.title.length)
{
// Shift the badge on the left to be close the back icon
frame.origin.x = ([GBDeviceInfo deviceInfo].displayInfo.display > GBDeviceDisplay4Inch ? -35 : -25);
}
else
{
frame.origin.x = 0;
}
}
// Caution: set label background view frame only in case of changes to prevent from looping on 'viewDidLayoutSubviews'.
if (!CGRectEqualToRect(missedDiscussionsBadgeLabelBgView.frame, frame))
{
missedDiscussionsBadgeLabelBgView.frame = frame;
// Adjust the custom view width of the associated bar button
CGRect bgFrame = missedDiscussionsBarButtonCustomView.frame;
CGFloat width = frame.size.width + frame.origin.x;
bgFrame.size.width = (width > 0 ? width : 0);
missedDiscussionsBarButtonCustomView.frame = bgFrame;
}
// Set the right background color
@ -4075,12 +4098,12 @@
if (readMarkerTableViewCell && isAppeared && !self.isBubbleTableViewDisplayInTransition)
{
// Check whether the read marker is visible
CGFloat contentTopPosY = self.bubblesTableView.contentOffset.y + self.bubblesTableView.contentInset.top;
CGFloat contentTopPosY = self.bubblesTableView.contentOffset.y + self.bubblesTableView.mxk_adjustedContentInset.top;
CGFloat readMarkerViewPosY = readMarkerTableViewCell.frame.origin.y + readMarkerTableViewCell.readMarkerView.frame.origin.y;
if (contentTopPosY <= readMarkerViewPosY)
{
// Compute the max vertical position visible according to contentOffset
CGFloat contentBottomPosY = self.bubblesTableView.contentOffset.y + self.bubblesTableView.frame.size.height - self.bubblesTableView.contentInset.bottom;
CGFloat contentBottomPosY = self.bubblesTableView.contentOffset.y + self.bubblesTableView.frame.size.height - self.bubblesTableView.mxk_adjustedContentInset.bottom;
if (readMarkerViewPosY <= contentBottomPosY)
{
// Launch animation
@ -4162,7 +4185,7 @@
// The read marker display is still enabled (see roomDataSource.showReadMarker flag),
// this means the read marker was not been visible yet.
// We show the banner if the marker is located in the top hidden part of the cell.
CGFloat contentTopPosY = self.bubblesTableView.contentOffset.y + self.bubblesTableView.contentInset.top;
CGFloat contentTopPosY = self.bubblesTableView.contentOffset.y + self.bubblesTableView.mxk_adjustedContentInset.top;
CGFloat readMarkerViewPosY = roomBubbleTableViewCell.frame.origin.y + roomBubbleTableViewCell.readMarkerView.frame.origin.y;
self.jumpToLastUnreadBannerContainer.hidden = (contentTopPosY < readMarkerViewPosY);
}

View file

@ -156,34 +156,47 @@
NSArray<NSString*> *roomDirectoryServers = [[NSUserDefaults standardUserDefaults] objectForKey:@"roomDirectoryServers"];
directoryServersDataSource.roomDirectoryServers = roomDirectoryServers;
__weak typeof(self) weakSelf = self;
[directoryServerPickerViewController displayWithDataSource:directoryServersDataSource onComplete:^(id<MXKDirectoryServerCellDataStoring> cellData) {
if (cellData)
if (weakSelf && cellData)
{
typeof(self) self = weakSelf;
// Use the selected directory server
if (cellData.thirdPartyProtocolInstance)
{
recentsDataSource.publicRoomsDirectoryDataSource.thirdpartyProtocolInstance = cellData.thirdPartyProtocolInstance;
self->recentsDataSource.publicRoomsDirectoryDataSource.thirdpartyProtocolInstance = cellData.thirdPartyProtocolInstance;
}
else if (cellData.homeserver)
{
recentsDataSource.publicRoomsDirectoryDataSource.includeAllNetworks = cellData.includeAllNetworks;
recentsDataSource.publicRoomsDirectoryDataSource.homeserver = cellData.homeserver;
self->recentsDataSource.publicRoomsDirectoryDataSource.includeAllNetworks = cellData.includeAllNetworks;
self->recentsDataSource.publicRoomsDirectoryDataSource.homeserver = cellData.homeserver;
}
// Refresh data
[self addSpinnerFooterView];
[recentsDataSource.publicRoomsDirectoryDataSource paginate:^(NSUInteger roomsAdded) {
[self->recentsDataSource.publicRoomsDirectoryDataSource paginate:^(NSUInteger roomsAdded) {
// The table view is automatically filled
[self removeSpinnerFooterView];
if (weakSelf)
{
typeof(self) self = weakSelf;
// Make the directory section appear full-page
[self.recentsTableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:recentsDataSource.directorySection] atScrollPosition:UITableViewScrollPositionTop animated:YES];
// The table view is automatically filled
[self removeSpinnerFooterView];
// Make the directory section appear full-page
[self.recentsTableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:self->recentsDataSource.directorySection] atScrollPosition:UITableViewScrollPositionTop animated:YES];
}
} failure:^(NSError *error) {
[self removeSpinnerFooterView];
if (weakSelf)
{
typeof(self) self = weakSelf;
[self removeSpinnerFooterView];
}
}];
}
}];

View file

@ -19,9 +19,8 @@
#import "DeviceView.h"
#import "MediaPickerViewController.h"
#import "TableViewCellWithCheckBoxes.h"
@interface SettingsViewController : MXKTableViewController<UITextFieldDelegate, MediaPickerViewControllerDelegate, MXKDeviceViewDelegate, UIDocumentInteractionControllerDelegate, MXKCountryPickerViewControllerDelegate, MXKLanguagePickerViewControllerDelegate, TableViewCellWithCheckBoxesDelegate>
@interface SettingsViewController : MXKTableViewController<UITextFieldDelegate, MediaPickerViewControllerDelegate, MXKDeviceViewDelegate, UIDocumentInteractionControllerDelegate, MXKCountryPickerViewControllerDelegate, MXKLanguagePickerViewControllerDelegate>
@end

View file

@ -39,7 +39,9 @@
#import "RiotDesignValues.h"
#import "TableViewCellWithPhoneNumberTextField.h"
static NSString* const kSettingsViewControllerPhoneBookCountryCellId = @"kSettingsViewControllerPhoneBookCountryCellId";
#import "GBDeviceInfo_iOS.h"
NSString* const kSettingsViewControllerPhoneBookCountryCellId = @"kSettingsViewControllerPhoneBookCountryCellId";
enum
{
@ -97,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,
@ -106,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
};
@ -212,9 +213,6 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)();
BOOL keepNewEmailEditing;
BOOL keepNewPhoneNumberEditing;
// The user interface theme cell
TableViewCellWithCheckBoxes *uiThemeCell;
// The current pushed view controller
UIViewController *pushedViewController;
}
@ -257,7 +255,6 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)();
[self.tableView registerClass:MXKTableViewCellWithLabelAndSwitch.class forCellReuseIdentifier:[MXKTableViewCellWithLabelAndSwitch defaultReuseIdentifier]];
[self.tableView registerClass:MXKTableViewCellWithLabelAndMXKImageView.class forCellReuseIdentifier:[MXKTableViewCellWithLabelAndMXKImageView defaultReuseIdentifier]];
[self.tableView registerClass:TableViewCellWithPhoneNumberTextField.class forCellReuseIdentifier:[TableViewCellWithPhoneNumberTextField defaultReuseIdentifier]];
[self.tableView registerClass:TableViewCellWithCheckBoxes.class forCellReuseIdentifier:[TableViewCellWithCheckBoxes defaultReuseIdentifier]];
// Enable self sizing cells
self.tableView.rowHeight = UITableViewAutomaticDimension;
@ -424,7 +421,7 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)();
// Observe kAppDelegateDidTapStatusBarNotificationObserver.
kAppDelegateDidTapStatusBarNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kAppDelegateDidTapStatusBarNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
[self.tableView setContentOffset:CGPointMake(-self.tableView.contentInset.left, -self.tableView.contentInset.top) animated:YES];
[self.tableView setContentOffset:CGPointMake(-self.tableView.mxk_adjustedContentInset.left, -self.tableView.mxk_adjustedContentInset.top) animated:YES];
}];
@ -1744,36 +1741,39 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)();
}
else if (row == USER_INTERFACE_THEME_INDEX)
{
uiThemeCell = [tableView dequeueReusableCellWithIdentifier:[TableViewCellWithCheckBoxes defaultReuseIdentifier] forIndexPath:indexPath];
uiThemeCell.mainContainerLeadingConstraint.constant = uiThemeCell.separatorInset.left;
uiThemeCell.checkBoxesNumber = 2;
uiThemeCell.allowsMultipleSelection = NO;
uiThemeCell.delegate = self;
NSArray *labels = uiThemeCell.labels;
UILabel *label;
label = labels[0];
label.textColor = kRiotPrimaryTextColor;
label.text = NSLocalizedStringFromTable(@"settings_ui_light_theme", @"Vector", nil);
label = labels[1];
label.textColor = kRiotPrimaryTextColor;
label.text = NSLocalizedStringFromTable(@"settings_ui_dark_theme", @"Vector", nil);
NSString *selectedTheme = [[NSUserDefaults standardUserDefaults] stringForKey:@"userInterfaceTheme"];
if (selectedTheme && [selectedTheme isEqualToString:@"dark"])
cell = [tableView dequeueReusableCellWithIdentifier:kSettingsViewControllerPhoneBookCountryCellId];
if (!cell)
{
[uiThemeCell setCheckBoxValue:YES atIndex:1];
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:kSettingsViewControllerPhoneBookCountryCellId];
}
else
NSString *theme = [[NSUserDefaults standardUserDefaults] stringForKey:@"userInterfaceTheme"];
if (!theme)
{
// Consider the light theme by default.
[uiThemeCell setCheckBoxValue:YES atIndex:0];
if (@available(iOS 11.0, *))
{
// "auto" is used the default value from iOS 11
theme = @"auto";
}
else
{
// Use "light" for older version
theme = @"light";
}
}
cell = uiThemeCell;
theme = [NSString stringWithFormat:@"settings_ui_theme_%@", theme];
NSString *i18nTheme = NSLocalizedStringFromTable(theme,
@"Vector",
nil);
cell.textLabel.textColor = kRiotPrimaryTextColor;
cell.textLabel.text = NSLocalizedStringFromTable(@"settings_ui_theme", @"Vector", nil);
cell.detailTextLabel.text = i18nTheme;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.selectionStyle = UITableViewCellSelectionStyleDefault;
}
}
else if (section == SETTINGS_SECTION_IGNORED_USERS_INDEX)
@ -1915,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]];
@ -2005,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];
@ -2018,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];
@ -2340,6 +2349,10 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)();
languagePickerViewController.delegate = self;
[self pushViewController:languagePickerViewController];
}
else if (row == USER_INTERFACE_THEME_INDEX)
{
[self showThemePicker];
}
}
else if (section == SETTINGS_SECTION_IGNORED_USERS_INDEX)
{
@ -2792,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])
@ -3512,6 +3538,90 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)();
}
}
- (void)showThemePicker
{
__weak typeof(self) weakSelf = self;
__block UIAlertAction *autoAction, *lightAction, *darkAction;
NSString *themePickerMessage;
void (^actionBlock)(UIAlertAction *action) = ^(UIAlertAction * action) {
if (weakSelf)
{
typeof(self) self = weakSelf;
NSString *newTheme;
if (action == autoAction)
{
newTheme = @"auto";
}
else if (action == lightAction)
{
newTheme = @"light";
}
else if (action == darkAction)
{
newTheme = @"dark";
}
NSString *theme = [[NSUserDefaults standardUserDefaults] stringForKey:@"userInterfaceTheme"];
if (newTheme && ![newTheme isEqualToString:theme])
{
// Clear fake Riot Avatars based on the previous theme.
[AvatarGenerator clear];
// The user wants to select this theme
[[NSUserDefaults standardUserDefaults] setObject:newTheme forKey:@"userInterfaceTheme"];
[[NSUserDefaults standardUserDefaults] synchronize];
[self.tableView reloadData];
}
}
};
if (@available(iOS 11.0, *))
{
// Show "auto" only from iOS 11
autoAction = [UIAlertAction actionWithTitle:NSLocalizedStringFromTable(@"settings_ui_theme_auto", @"Vector", nil)
style:UIAlertActionStyleDefault
handler:actionBlock];
// Explain what is "auto"
themePickerMessage = NSLocalizedStringFromTable(@"settings_ui_theme_picker_message", @"Vector", nil);
}
lightAction = [UIAlertAction actionWithTitle:NSLocalizedStringFromTable(@"settings_ui_theme_light", @"Vector", nil)
style:UIAlertActionStyleDefault
handler:actionBlock];
darkAction = [UIAlertAction actionWithTitle:NSLocalizedStringFromTable(@"settings_ui_theme_dark", @"Vector", nil)
style:UIAlertActionStyleDefault
handler:actionBlock];
UIAlertController *themePicker = [UIAlertController alertControllerWithTitle:NSLocalizedStringFromTable(@"settings_ui_theme_picker_title", @"Vector", nil)
message:themePickerMessage
preferredStyle:UIAlertControllerStyleActionSheet];
if (autoAction)
{
[themePicker addAction:autoAction];
}
[themePicker addAction:lightAction];
[themePicker addAction:darkAction];
// Cancel button
[themePicker addAction:[UIAlertAction actionWithTitle:[NSBundle mxk_localizedStringForKey:@"cancel"]
style:UIAlertActionStyleDefault
handler:nil]];
UIView *fromCell = [self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:USER_INTERFACE_THEME_INDEX inSection:SETTINGS_SECTION_USER_INTERFACE_INDEX]];
[themePicker popoverPresentationController].sourceView = fromCell;
[themePicker popoverPresentationController].sourceRect = fromCell.bounds;
[self presentViewController:themePicker animated:YES completion:nil];
}
#pragma mark - MediaPickerViewController Delegate
- (void)dismissMediaPicker
@ -3851,25 +3961,4 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)();
}
}
#pragma mark - TableViewCellWithCheckBoxesDelegate
- (void)tableViewCellWithCheckBoxes:(TableViewCellWithCheckBoxes *)tableViewCellWithCheckBoxes didTapOnCheckBoxAtIndex:(NSUInteger)index
{
if (tableViewCellWithCheckBoxes == uiThemeCell)
{
NSString *theme = (index == 0) ? @"light" : @"dark";
BOOL isCurrentlySelected = [uiThemeCell checkBoxValueAtIndex:index];
if (!isCurrentlySelected)
{
// Clear fake Riot Avatars based on the previous theme.
[AvatarGenerator clear];
// The user wants to select this theme
[[NSUserDefaults standardUserDefaults] setObject:theme forKey:@"userInterfaceTheme"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
}
}
@end

View file

@ -0,0 +1,56 @@
/*
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 <UIKit/UIKit.h>
#import <MatrixSDK/MatrixSDK.h>
#import <MatrixKit/MatrixKit.h>
/**
`WidgetPickerViewController` displays the list of widgets within a room plus a
way to open the integration manager for this room.
TODO: The feature is still in dev. WidgetPickerViewController` is not yet a pure
UIViewController.
As there is no specified design, the list is displayed in a simple UIAlertController.
It would be nice if this picker could directly:
- Remove a widget
- Launch the integration manager to edit a widget
- Automatically updates on widgets change
*/
@interface WidgetPickerViewController : NSObject
/**
The UIAlertController instance which handles the dialog.
*/
@property (nonatomic, readonly) UIAlertController *alertController;
/**
Create the `WidgetPickerViewController` instance.
@param mxSession the session to use.
@param roomId the room where to list available widgets.
*/
- (instancetype)initForMXSession:(MXSession*)mxSession inRoom:(NSString*)roomId;
/**
Show the dialog in a given view controller.
@param mxkViewController the mxkViewController where to show the dialog.
*/
- (void)showInViewController:(MXKViewController*)mxkViewController;
@end

View file

@ -0,0 +1,99 @@
/*
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 "WidgetPickerViewController.h"
#import "AppDelegate.h"
#import "WidgetManager.h"
#import "WidgetViewController.h"
#import "IntegrationManagerViewController.h"
@interface WidgetPickerViewController ()
{
MXSession *mxSession;
NSString *roomId;
}
@end
@implementation WidgetPickerViewController
- (instancetype)initForMXSession:(MXSession*)theMXSession inRoom:(NSString*)theRoomId
{
self = [super init];
if (self)
{
mxSession = theMXSession;
roomId = theRoomId;
_alertController = [UIAlertController alertControllerWithTitle:@"Matrix Apps"
message:nil
preferredStyle:UIAlertControllerStyleAlert];
}
return self;
}
- (void)showInViewController:(MXKViewController *)mxkViewController
{
UIAlertAction *alertAction;
MXRoom *room = [mxSession roomWithRoomId:roomId];
NSArray<Widget*> *widgets = [[WidgetManager sharedManager] widgetsNotOfTypes:@[kWidgetTypeJitsi]
inRoom:room];
// List widgets
for (Widget *widget in widgets)
{
alertAction = [UIAlertAction actionWithTitle:widget.name
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * _Nonnull action)
{
// Hide back button title
mxkViewController.navigationItem.backBarButtonItem =[[UIBarButtonItem alloc] initWithTitle:@"" style:UIBarButtonItemStylePlain target:nil action:nil];
// Display the widget
WidgetViewController *widgetVC = [[WidgetViewController alloc] initForWidget:widget];
[mxkViewController.navigationController pushViewController:widgetVC animated:YES];
}];
[_alertController addAction:alertAction];
}
// Link to the integration manager
alertAction = [UIAlertAction actionWithTitle:@"Manage integrations..."
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * _Nonnull action)
{
IntegrationManagerViewController *modularVC = [[IntegrationManagerViewController alloc] initForMXSession:self->mxSession
inRoom:self->roomId
screen:kIntegrationManagerMainScreen
widgetId:nil];
[mxkViewController presentViewController:modularVC animated:NO completion:nil];
}];
[_alertController addAction:alertAction];
// Cancel
alertAction = [UIAlertAction actionWithTitle:[NSBundle mxk_localizedStringForKey:@"cancel"]
style:UIAlertActionStyleCancel
handler:nil];
[_alertController addAction:alertAction];
// And show it
[mxkViewController presentViewController:_alertController animated:YES completion:nil];
}
@end

View file

@ -20,6 +20,8 @@
- (void)prepareForReuse
{
[super prepareForReuse];
if (self.heightConstraint != 0)
{
self.heightConstraint = 0;

View file

@ -45,6 +45,8 @@
- (void)prepareForReuse
{
[super prepareForReuse];
if (self.pictureViewTopConstraint.constant != xibPictureViewTopConstraintConstant)
{
self.pictureViewTopConstraint.constant = xibPictureViewTopConstraintConstant;

View file

@ -45,6 +45,8 @@
- (void)prepareForReuse
{
[super prepareForReuse];
// Reset avatars
for (UIView *avatarView in self.avatarsView.subviews)
{

View file

@ -0,0 +1,41 @@
/*
Copyright 2015 OpenMarket Ltd
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 <HPGrowingTextView.h>
#import "RoomInputToolbarView.h"
@interface KeyboardGrowingTextView: HPGrowingTextView
- (NSArray<UIKeyCommand *> *)keyCommands;
@end
@implementation KeyboardGrowingTextView
- (NSArray<UIKeyCommand *> *)keyCommands {
return @[
[UIKeyCommand keyCommandWithInput:@"\r" modifierFlags:0 action:@selector(keyCommandSelector:)]
];
}
- (void)keyCommandSelector:(UIKeyCommand *)sender {
if ([sender.input isEqualToString:@"\r"] && [self.delegate isKindOfClass: RoomInputToolbarView.class]){
RoomInputToolbarView *ritv = (RoomInputToolbarView *)self.delegate;
[ritv onTouchUpInside:ritv.rightInputToolbarButton]; // touch the Send button.
}
}
@end

View file

@ -46,7 +46,7 @@
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="QWp-NV-uh5" userLabel="Message Composer Container">
<rect key="frame" x="62" y="4" width="443" height="38"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="wgb-ON-N29" customClass="HPGrowingTextView">
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="wgb-ON-N29" customClass="KeyboardGrowingTextView">
<rect key="frame" x="0.0" y="0.0" width="443" height="38"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<accessibility key="accessibilityConfiguration" identifier="GrowingTextView"/>

View file

@ -16,6 +16,20 @@
#import <MatrixKit/MatrixKit.h>
// We add here a protocol to handle title view layout update.
@class RoomMemberTitleView;
@protocol RoomMemberTitleViewDelegate <NSObject>
@optional
/**
Tells the delegate that the layout has been updated.
@param titleView the room member title view.
*/
- (void)roomMemberTitleViewDidLayoutSubview:(RoomMemberTitleView*)titleView;
@end
@interface RoomMemberTitleView : MXKView
/**
@ -38,4 +52,9 @@
@property (weak, nonatomic) IBOutlet UIImageView *memberBadge;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *memberAvatarCenterXConstraint;
/**
The delegate.
*/
@property (nonatomic) id<RoomMemberTitleViewDelegate> delegate;
@end

View file

@ -40,29 +40,60 @@
if (self.superview)
{
// Center horizontally the avatar into the navigation bar
CGRect frame = self.superview.frame;
UINavigationBar *navigationBar;
UIView *superView = self;
while (superView.superview)
if (@available(iOS 11.0, *))
{
if ([superView.superview isKindOfClass:[UINavigationBar class]])
// Force the title view layout by adding 2 new constraints on the UINavigationBarContentView instance.
NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:self
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.superview
attribute:NSLayoutAttributeTop
multiplier:1.0f
constant:0.0f];
NSLayoutConstraint *centerXConstraint = [NSLayoutConstraint constraintWithItem:self
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self.superview
attribute:NSLayoutAttributeCenterX
multiplier:1.0f
constant:0.0f];
[NSLayoutConstraint activateConstraints:@[topConstraint, centerXConstraint]];
// Do not crop the avatar
self.superview.clipsToBounds = NO;
}
else
{
// Center horizontally the avatar into the navigation bar
CGRect frame = self.superview.frame;
UINavigationBar *navigationBar;
UIView *superView = self;
while (superView.superview)
{
navigationBar = (UINavigationBar*)superView.superview;
break;
if ([superView.superview isKindOfClass:[UINavigationBar class]])
{
navigationBar = (UINavigationBar*)superView.superview;
break;
}
superView = superView.superview;
}
superView = superView.superview;
}
if (navigationBar)
{
CGSize navBarSize = navigationBar.frame.size;
CGFloat superviewCenterX = frame.origin.x + (frame.size.width / 2);
self.memberAvatarCenterXConstraint.constant = (navBarSize.width / 2) - superviewCenterX;
if (navigationBar)
{
CGSize navBarSize = navigationBar.frame.size;
CGFloat superviewCenterX = frame.origin.x + (frame.size.width / 2);
self.memberAvatarCenterXConstraint.constant = (navBarSize.width / 2) - superviewCenterX;
}
}
}
if (_delegate && [_delegate respondsToSelector:@selector(roomMemberTitleViewDidLayoutSubview:)])
{
[_delegate roomMemberTitleViewDidLayoutSubview:self];
}
}
@end

View file

@ -40,27 +40,53 @@
if (self.superview)
{
// Center horizontally the avatar into the navigation bar
CGRect frame = self.superview.frame;
UINavigationBar *navigationBar;
UIView *superView = self;
while (superView.superview)
if (@available(iOS 11.0, *))
{
if ([superView.superview isKindOfClass:[UINavigationBar class]])
// Force the title view layout by adding 2 new constraints on the UINavigationBarContentView instance.
NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:self
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.superview
attribute:NSLayoutAttributeTop
multiplier:1.0f
constant:0.0f];
NSLayoutConstraint *centerXConstraint = [NSLayoutConstraint constraintWithItem:self
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self.superview
attribute:NSLayoutAttributeCenterX
multiplier:1.0f
constant:0.0f];
[NSLayoutConstraint activateConstraints:@[topConstraint, centerXConstraint]];
// Do not crop the avatar
self.superview.clipsToBounds = NO;
}
else
{
// Center horizontally the avatar into the navigation bar
CGRect frame = self.superview.frame;
UINavigationBar *navigationBar;
UIView *superView = self;
while (superView.superview)
{
navigationBar = (UINavigationBar*)superView.superview;
break;
if ([superView.superview isKindOfClass:[UINavigationBar class]])
{
navigationBar = (UINavigationBar*)superView.superview;
break;
}
superView = superView.superview;
}
superView = superView.superview;
}
if (navigationBar)
{
CGSize navBarSize = navigationBar.frame.size;
CGFloat superviewCenterX = frame.origin.x + (frame.size.width / 2);
self.roomAvatarCenterXConstraint.constant = (navBarSize.width / 2) - superviewCenterX;
if (navigationBar)
{
CGSize navBarSize = navigationBar.frame.size;
CGFloat superviewCenterX = frame.origin.x + (frame.size.width / 2);
self.roomAvatarCenterXConstraint.constant = (navBarSize.width / 2) - superviewCenterX;
}
}
}
}

View file

@ -73,35 +73,59 @@
if (self.superview)
{
// Center horizontally the display name into the navigation bar
CGRect frame = self.superview.frame;
// Look for the navigation bar.
UINavigationBar *navigationBar;
UIView *superView = self;
while (superView.superview)
if (@available(iOS 11.0, *))
{
if ([superView.superview isKindOfClass:[UINavigationBar class]])
{
navigationBar = (UINavigationBar*)superView.superview;
break;
}
// Force the title view layout by adding 2 new constraints on the UINavigationBarContentView instance.
NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:self
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.superview
attribute:NSLayoutAttributeTop
multiplier:1.0f
constant:0.0f];
NSLayoutConstraint *centerXConstraint = [NSLayoutConstraint constraintWithItem:self
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self.superview
attribute:NSLayoutAttributeCenterX
multiplier:1.0f
constant:0.0f];
[NSLayoutConstraint activateConstraints:@[topConstraint, centerXConstraint]];
superView = superView.superview;
}
if (navigationBar)
else
{
CGSize navBarSize = navigationBar.frame.size;
CGFloat superviewCenterX = frame.origin.x + (frame.size.width / 2);
// Center horizontally the display name into the navigation bar
CGRect frame = self.superview.frame;
// Check whether the view is not moving away (see navigation between view controllers).
if (superviewCenterX < navBarSize.width)
// Look for the navigation bar.
UINavigationBar *navigationBar;
UIView *superView = self;
while (superView.superview)
{
// Center the display name
self.displayNameCenterXConstraint.constant = (navBarSize.width / 2) - superviewCenterX;
if ([superView.superview isKindOfClass:[UINavigationBar class]])
{
navigationBar = (UINavigationBar*)superView.superview;
break;
}
superView = superView.superview;
}
}
if (navigationBar)
{
CGSize navBarSize = navigationBar.frame.size;
CGFloat superviewCenterX = frame.origin.x + (frame.size.width / 2);
// Check whether the view is not moving away (see navigation between view controllers).
if (superviewCenterX < navBarSize.width)
{
// Center the display name
self.displayNameCenterXConstraint.constant = (navBarSize.width / 2) - superviewCenterX;
}
}
}
}
}

View file

@ -38,29 +38,52 @@
if (self.superview)
{
// Center horizontally the display name into the navigation bar
CGRect frame = self.superview.frame;
UINavigationBar *navigationBar;
UIView *superView = self;
while (superView.superview)
if (@available(iOS 11.0, *))
{
if ([superView.superview isKindOfClass:[UINavigationBar class]])
// Force the title view layout by adding 2 new constraints on the UINavigationBarContentView instance.
NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:self
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.superview
attribute:NSLayoutAttributeTop
multiplier:1.0f
constant:0.0f];
NSLayoutConstraint *centerXConstraint = [NSLayoutConstraint constraintWithItem:self
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self.superview
attribute:NSLayoutAttributeCenterX
multiplier:1.0f
constant:0.0f];
[NSLayoutConstraint activateConstraints:@[topConstraint, centerXConstraint]];
}
else
{
// Center horizontally the display name into the navigation bar
CGRect frame = self.superview.frame;
UINavigationBar *navigationBar;
UIView *superView = self;
while (superView.superview)
{
navigationBar = (UINavigationBar*)superView.superview;
break;
if ([superView.superview isKindOfClass:[UINavigationBar class]])
{
navigationBar = (UINavigationBar*)superView.superview;
break;
}
superView = superView.superview;
}
superView = superView.superview;
if (navigationBar)
{
CGSize navBarSize = navigationBar.frame.size;
CGFloat superviewCenterX = frame.origin.x + (frame.size.width / 2);
// Center the display name
self.displayNameCenterXConstraint.constant = (navBarSize.width / 2) - superviewCenterX;
}
}
if (navigationBar)
{
CGSize navBarSize = navigationBar.frame.size;
CGFloat superviewCenterX = frame.origin.x + (frame.size.width / 2);
// Center the display name
self.displayNameCenterXConstraint.constant = (navBarSize.width / 2) - superviewCenterX;
}
}
}

View file

@ -17,7 +17,7 @@
<key>CFBundlePackageType</key>
<string>XPC!</string>
<key>CFBundleShortVersionString</key>
<string>0.5.3</string>
<string>0.5.5</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>NSExtension</key>

View file

@ -0,0 +1,38 @@
/*
Copyright 2017 Aram Sargsyan
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 <MatrixKit/MatrixKit.h>
typedef NS_ENUM(NSInteger, ShareDataSourceMode)
{
DataSourceModePeople,
DataSourceModeRooms
};
@interface ShareDataSource : MXKRecentsDataSource
- (instancetype)initWithMode:(ShareDataSourceMode)dataSourceMode;
/**
Returns the cell data at the index path
@param indexPath the index of the cell
@return the MXKRecentCellData instance if it exists
*/
- (MXKRecentCellData *)cellDataAtIndexPath:(NSIndexPath *)indexPath;
@end

View file

@ -0,0 +1,174 @@
/*
Copyright 2017 Aram Sargsyan
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 "ShareDataSource.h"
#import "ShareExtensionManager.h"
#import "RecentRoomTableViewCell.h"
@interface ShareDataSource ()
@property (nonatomic, readwrite) ShareDataSourceMode dataSourceMode;
@property NSArray <MXKRecentCellData *> *recentCellDatas;
@property NSMutableArray <MXKRecentCellData *> *visibleRoomCellDatas;
@end
@implementation ShareDataSource
- (instancetype)initWithMode:(ShareDataSourceMode)dataSourceMode
{
self = [super init];
if (self)
{
self.dataSourceMode = dataSourceMode;
[self loadCellData];
}
return self;
}
- (void)destroy
{
[super destroy];
_recentCellDatas = nil;
_visibleRoomCellDatas = nil;
}
#pragma mark - Private
- (void)loadCellData
{
[[ShareExtensionManager sharedManager].fileStore asyncRoomsSummaries:^(NSArray<MXRoomSummary *> * _Nonnull roomsSummaries) {
NSMutableArray *cellData = [NSMutableArray array];
for (MXRoomSummary *roomSummary in roomsSummaries)
{
MXKRecentCellData *recentCellData = [[MXKRecentCellData alloc] initWithRoomSummary:roomSummary andRecentListDataSource:nil];
if ((self.dataSourceMode == DataSourceModeRooms) ^ roomSummary.isDirect)
{
[cellData addObject:recentCellData];
}
}
// Sort rooms according to their last messages (most recent first)
NSComparator comparator = ^NSComparisonResult(MXKRecentCellData *recentCellData1, MXKRecentCellData *recentCellData2) {
NSComparisonResult result = NSOrderedAscending;
if (recentCellData2.roomSummary.lastMessageOriginServerTs > recentCellData1.roomSummary.lastMessageOriginServerTs)
{
result = NSOrderedDescending;
}
else if (recentCellData2.roomSummary.lastMessageOriginServerTs == recentCellData1.roomSummary.lastMessageOriginServerTs)
{
result = NSOrderedSame;
}
return result;
};
[cellData sortUsingComparator:comparator];
self.recentCellDatas = cellData;
dispatch_async(dispatch_get_main_queue(), ^{
[self.delegate dataSource:self didCellChange:nil];
});
} failure:^(NSError * _Nonnull error) {
NSLog(@"[ShareDataSource failed to get room summaries]");
}];
}
#pragma mark - MXKRecentsDataSource
- (MXKRecentCellData *)cellDataAtIndexPath:(NSIndexPath *)indexPath
{
if (self.visibleRoomCellDatas)
{
return self.visibleRoomCellDatas[indexPath.row];
}
return self.recentCellDatas[indexPath.row];
}
- (void)searchWithPatterns:(NSArray *)patternsList
{
if (self.visibleRoomCellDatas)
{
[self.visibleRoomCellDatas removeAllObjects];
}
else
{
self.visibleRoomCellDatas = [NSMutableArray arrayWithCapacity:self.recentCellDatas.count];
}
if (patternsList.count)
{
for (MXKRecentCellData *cellData in self.recentCellDatas)
{
for (NSString* pattern in patternsList)
{
if (cellData.roomSummary.displayname && [cellData.roomSummary.displayname rangeOfString:pattern options:NSCaseInsensitiveSearch].location != NSNotFound)
{
[self.visibleRoomCellDatas addObject:cellData];
break;
}
}
}
}
else
{
self.visibleRoomCellDatas = nil;
}
[self.delegate dataSource:self didCellChange:nil];
}
#pragma mark - UITableViewDataSource
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (self.visibleRoomCellDatas)
{
return self.visibleRoomCellDatas.count;
}
return self.recentCellDatas.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
RecentRoomTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:[RecentRoomTableViewCell defaultReuseIdentifier]];
[cell render:[self cellDataAtIndexPath:indexPath]];
return cell;
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
return NO;
}
@end

View file

@ -21,10 +21,11 @@
@class SharePresentingViewController;
/**
Posted when the matrix session has been changed.
The notification object is the matrix session.
Posted when the matrix user account and his data has been checked and updated.
The notification object is the MXKAccount instance.
*/
extern NSString *const kShareExtensionManagerDidChangeMXSessionNotification;
extern NSString *const kShareExtensionManagerDidUpdateAccountDataNotification;
/**
The protocol for the manager's delegate
@ -42,6 +43,11 @@ extern NSString *const kShareExtensionManagerDidChangeMXSessionNotification;
@optional
/**
Called when the manager starts sending the content to a room
@param extensionManager the ShareExtensionManager object that called the method
@param room the room where content will be sent
*/
- (void)shareExtensionManager:(ShareExtensionManager *)extensionManager didStartSendingContentToRoom:(MXRoom *)room;
/**
@ -71,9 +77,14 @@ extern NSString *const kShareExtensionManagerDidChangeMXSessionNotification;
@property (nonatomic) SharePresentingViewController *primaryViewController;
/**
The associated matrix session (nil by default).
The current user account
*/
@property (nonatomic, readonly) MXSession *mxSession;
@property (nonatomic, readonly) MXKAccount *userAccount;
/**
The shared file store
*/
@property (nonatomic, readonly) MXFileStore *fileStore;
/**
A delegate used to notify about needed UI changes when sharing
@ -89,9 +100,9 @@ extern NSString *const kShareExtensionManagerDidChangeMXSessionNotification;
Send the content that the user has chosen to a room
@param room the room to send the content to
@param failureBlock the code to be executed when sharing has failed for whatever reason
note: there is no "successBlock" parameter because when the sharing succeds, the extension needs to close itself
note: there is no "successBlock" parameter because when the sharing succeeds, the extension needs to close itself
*/
- (void)sendContentToRoom:(MXRoom *)room failureBlock:(void(^)())failureBlock;
- (void)sendContentToRoom:(MXRoom *)room failureBlock:(void(^)(NSError *error))failureBlock;
/**
Checks if there is an image in the user chosen content
@ -106,3 +117,10 @@ extern NSString *const kShareExtensionManagerDidChangeMXSessionNotification;
- (void)terminateExtensionCanceled:(BOOL)canceled;
@end
@interface NSItemProvider (ShareExtensionManager)
@property BOOL isLoaded;
@end

View file

@ -18,8 +18,9 @@
#import "SharePresentingViewController.h"
#import "MXKPieChartHUD.h"
@import MobileCoreServices;
#import "objc/runtime.h"
NSString *const kShareExtensionManagerDidChangeMXSessionNotification = @"kShareExtensionManagerDidChangeMXSessionNotification";
NSString *const kShareExtensionManagerDidUpdateAccountDataNotification = @"kShareExtensionManagerDidUpdateAccountDataNotification";
typedef NS_ENUM(NSInteger, ImageCompressionMode)
{
@ -29,13 +30,15 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode)
ImageCompressionModeLarge
};
@interface ShareExtensionManager ()
// The current user account
@property (nonatomic) MXKAccount *userAccount;
@property (nonatomic, readwrite) MXKAccount *userAccount;
@property ImageCompressionMode imageCompressionMode;
@property CGFloat actualLargeSize;
@property (nonatomic) NSMutableArray <NSData *> *pendingImages;
@property (nonatomic) NSMutableDictionary <NSString *, NSNumber *> *imageUploadProgresses;
@property (nonatomic) ImageCompressionMode imageCompressionMode;
@property (nonatomic) CGFloat actualLargeSize;
@end
@ -52,6 +55,9 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode)
sharedInstance = [[self alloc] init];
sharedInstance.pendingImages = [NSMutableArray array];
sharedInstance.imageUploadProgresses = [NSMutableDictionary dictionary];
[[NSNotificationCenter defaultCenter] addObserver:sharedInstance selector:@selector(onMediaUploadProgress:) name:kMXMediaUploadProgressNotification object:nil];
// Add observer to handle logout
@ -59,14 +65,15 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode)
// Add observer on the Extension host
[[NSNotificationCenter defaultCenter] addObserver:sharedInstance selector:@selector(checkUserAccount) name:NSExtensionHostWillEnterForegroundNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:sharedInstance selector:@selector(suspendSession) name:NSExtensionHostDidEnterBackgroundNotification object:nil];
MXSDKOptions *sdkOptions = [MXSDKOptions sharedInstance];
// Apply the application group
sdkOptions.applicationGroupIdentifier = @"group.im.vector";
// Disable identicon use
sdkOptions.disableIdenticonUseForUserAvatar = YES;
// Enable e2e encryption for newly created MXSession
sdkOptions.enableCryptoWhenStartingMXSession = YES;
});
return sharedInstance;
}
@ -85,48 +92,31 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode)
if (!firstAccount || ![self.userAccount.mxCredentials.accessToken isEqualToString:firstAccount.mxCredentials.accessToken])
{
// Remove this account
[self.userAccount closeSession:YES];
self.userAccount = nil;
_mxSession = nil;
// Post notification
[[NSNotificationCenter defaultCenter] postNotificationName:kShareExtensionManagerDidChangeMXSessionNotification object:_mxSession userInfo:nil];
}
}
if (!self.userAccount)
{
// We consider the first enabled account.
// TODO: Handle multiple accounts
self.userAccount = [MXKAccountManager sharedManager].activeAccounts.firstObject;
}
// Reset the file store to reload the room data.
if (_fileStore)
{
[_fileStore close];
_fileStore = nil;
}
if (self.userAccount)
{
// Resume the matrix session
[self.userAccount resume];
_fileStore = [[MXFileStore alloc] initWithCredentials:self.userAccount.mxCredentials];
}
else
{
// Prepare a new session if a new account is available.
[self prepareSession];
}
}
- (void)prepareSession
{
// We consider the first enabled account.
// TODO: Handle multiple accounts
self.userAccount = [MXKAccountManager sharedManager].activeAccounts.firstObject;
if (self.userAccount)
{
NSLog(@"[ShareExtensionManager] openSession for %@ account", self.userAccount.mxCredentials.userId);
// Use MXFileStore as MXStore to permanently store events.
[self.userAccount openSessionWithStore:[[MXFileStore alloc] init]];
_mxSession = self.userAccount.mxSession;
// Post notification
[[NSNotificationCenter defaultCenter] postNotificationName:kShareExtensionManagerDidChangeMXSessionNotification object:_mxSession userInfo:nil];
}
}
- (void)suspendSession
{
[self.userAccount pauseInBackgroundTask];
// Post notification
[[NSNotificationCenter defaultCenter] postNotificationName:kShareExtensionManagerDidUpdateAccountDataNotification object:self.userAccount userInfo:nil];
}
#pragma mark - Public
@ -135,11 +125,11 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode)
{
_shareExtensionContext = shareExtensionContext;
// Prepare or resume the matrix session.
// Check the current matrix user.
[self checkUserAccount];
}
- (void)sendContentToRoom:(MXRoom *)room failureBlock:(void(^)())failureBlock
- (void)sendContentToRoom:(MXRoom *)room failureBlock:(void(^)(NSError *error))failureBlock
{
NSString *UTTypeText = (__bridge NSString *)kUTTypeText;
NSString *UTTypeURL = (__bridge NSString *)kUTTypeURL;
@ -150,6 +140,8 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode)
__weak typeof(self) weakSelf = self;
[self.pendingImages removeAllObjects];
for (NSExtensionItem *item in self.shareExtensionContext.inputItems)
{
for (NSItemProvider *itemProvider in item.attachments)
@ -207,30 +199,24 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode)
}
else if ([itemProvider hasItemConformingToTypeIdentifier:UTTypeImage])
{
[itemProvider loadItemForTypeIdentifier:UTTypeImage options:nil completionHandler:^(NSData *imageData, NSError * _Null_unspecified error) {
// Switch back on the main thread to handle correctly the UI change
dispatch_async(dispatch_get_main_queue(), ^{
if (weakSelf)
{
typeof(self) self = weakSelf;
UIImage *image = [[UIImage alloc] initWithData:imageData];
UIAlertController *compressionPrompt = [self compressionPromptForImage:image shareBlock:^{
[self sendImage:image withProvider:itemProvider toRoom:room extensionItem:item failureBlock:failureBlock];
}];
if (compressionPrompt)
{
[self.delegate shareExtensionManager:self showImageCompressionPrompt:compressionPrompt];
}
}
itemProvider.isLoaded = NO;
[itemProvider loadItemForTypeIdentifier:UTTypeImage options:nil completionHandler:^(NSData *imageData, NSError * _Null_unspecified error)
{
if (weakSelf)
{
itemProvider.isLoaded = YES;
[self.pendingImages addObject:imageData];
});
if ([self areAttachmentsFullyLoaded])
{
UIImage *firstImage = [UIImage imageWithData:self.pendingImages.firstObject];
UIAlertController *compressionPrompt = [self compressionPromptForImage:firstImage shareBlock:^{
[self sendImages:self.pendingImages withProviders:item.attachments toRoom:room extensionItem:item failureBlock:failureBlock];
}];
[self.delegate shareExtensionManager:self showImageCompressionPrompt:compressionPrompt];
}
}
}];
}
else if ([itemProvider hasItemConformingToTypeIdentifier:UTTypeVideo])
@ -288,8 +274,6 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode)
- (void)terminateExtensionCanceled:(BOOL)canceled
{
[self suspendSession];
if (canceled)
{
[self.shareExtensionContext cancelRequestWithError:[NSError errorWithDomain:@"MXUserCancelErrorDomain" code:4201 userInfo:nil]];
@ -303,12 +287,24 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode)
self.primaryViewController = nil;
}
- (void)roomFromRoomSummary:(MXRoomSummary *)roomSummary store:(MXFileStore *)fileStore session:(MXSession *)session
{
[fileStore asyncAccountDataOfRoom:roomSummary.roomId success:^(MXRoomAccountData * _Nonnull accountData) {
[fileStore asyncStateEventsOfRoom:roomSummary.roomId success:^(NSArray<MXEvent *> * _Nonnull roomStateEvents) {
MXRoom *room = [[MXRoom alloc] initWithRoomId:roomSummary.roomId andMatrixSession:session andStateEvents:roomStateEvents andAccountData:accountData];
} failure:^(NSError * _Nonnull error) {
//sjh
}];
} failure:^(NSError * _Nonnull error) {
//shj
}];
}
#pragma mark - Private
- (void)completeRequestReturningItems:(nullable NSArray *)items completionHandler:(void(^ __nullable)(BOOL expired))completionHandler;
{
[self suspendSession];
[self.shareExtensionContext completeRequestReturningItems:items completionHandler:completionHandler];
[self.primaryViewController destroy];
@ -471,19 +467,44 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode)
}
}
- (BOOL)areAttachmentsFullyLoaded
{
for (NSExtensionItem *item in self.shareExtensionContext.inputItems)
{
for (NSItemProvider *itemProvider in item.attachments)
{
if (itemProvider.isLoaded == NO)
{
return NO;
}
}
}
return YES;
}
#pragma mark - Notifications
- (void)onMediaUploadProgress:(NSNotification *)notification
{
self.imageUploadProgresses[notification.object] = (NSNumber *)notification.userInfo[kMXMediaLoaderProgressValueKey];
if ([self.delegate respondsToSelector:@selector(shareExtensionManager:mediaUploadProgress:)])
{
[self.delegate shareExtensionManager:self mediaUploadProgress:((NSNumber *)notification.userInfo[kMXMediaLoaderProgressValueKey]).floatValue];
const NSInteger totalImagesCount = self.pendingImages.count;
CGFloat totalProgress = 0.0;
for (NSNumber *progress in self.imageUploadProgresses.allValues)
{
totalProgress += progress.floatValue/totalImagesCount;
}
[self.delegate shareExtensionManager:self mediaUploadProgress:totalProgress];
}
}
#pragma mark - Sharing
- (void)sendText:(NSString *)text toRoom:(MXRoom *)room extensionItem:(NSExtensionItem *)extensionItem failureBlock:(void(^)())failureBlock
- (void)sendText:(NSString *)text toRoom:(MXRoom *)room extensionItem:(NSExtensionItem *)extensionItem failureBlock:(void(^)(NSError *error))failureBlock
{
[self didStartSendingToRoom:room];
if (!text)
@ -491,13 +512,12 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode)
NSLog(@"[ShareExtensionManager] loadItemForTypeIdentifier: failed.");
if (failureBlock)
{
failureBlock();
failureBlock(nil);
}
return;
}
__weak typeof(self) weakSelf = self;
[room sendTextMessage:text success:^(NSString *eventId) {
if (weakSelf)
{
@ -508,12 +528,12 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode)
NSLog(@"[ShareExtensionManager] sendTextMessage failed.");
if (failureBlock)
{
failureBlock();
failureBlock(error);
}
}];
}
- (void)sendFileWithUrl:(NSURL *)fileUrl toRoom:(MXRoom *)room extensionItem:(NSExtensionItem *)extensionItem failureBlock:(void(^)())failureBlock
- (void)sendFileWithUrl:(NSURL *)fileUrl toRoom:(MXRoom *)room extensionItem:(NSExtensionItem *)extensionItem failureBlock:(void(^)(NSError *error))failureBlock
{
[self didStartSendingToRoom:room];
if (!fileUrl)
@ -521,7 +541,7 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode)
NSLog(@"[ShareExtensionManager] loadItemForTypeIdentifier: failed.");
if (failureBlock)
{
failureBlock();
failureBlock(nil);
}
return;
}
@ -543,85 +563,108 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode)
NSLog(@"[ShareExtensionManager] sendFile failed.");
if (failureBlock)
{
failureBlock();
failureBlock(error);
}
} keepActualFilename:YES];
}
- (void)sendImage:(UIImage *)image withProvider:(NSItemProvider*)itemProvider toRoom:(MXRoom *)room extensionItem:(NSExtensionItem *)extensionItem failureBlock:(void(^)())failureBlock
- (void)sendImages:(NSMutableArray *)imageDatas withProviders:(NSArray*)itemProviders toRoom:(MXRoom *)room extensionItem:(NSExtensionItem *)extensionItem failureBlock:(void(^)(NSError *error))failureBlock
{
[self didStartSendingToRoom:room];
if (!image)
for (NSInteger index = 0; index < imageDatas.count; index++)
{
NSLog(@"[ShareExtensionManager] loadItemForTypeIdentifier: failed.");
if (failureBlock)
NSItemProvider *itemProvider = itemProviders[index];
NSData *imageData = imageDatas[index];
UIImage *image = [UIImage imageWithData:imageData];
if (!imageData)
{
failureBlock();
NSLog(@"[ShareExtensionManager] loadItemForTypeIdentifier: failed.");
if (failureBlock)
{
failureBlock(nil);
failureBlock = nil;
}
return;
}
return;
}
// Prepare the image
NSData *imageData;
if (self.imageCompressionMode == ImageCompressionModeSmall)
{
image = [MXKTools reduceImage:image toFitInSize:CGSizeMake(MXKTOOLS_SMALL_IMAGE_SIZE, MXKTOOLS_SMALL_IMAGE_SIZE)];
}
else if (self.imageCompressionMode == ImageCompressionModeMedium)
{
image = [MXKTools reduceImage:image toFitInSize:CGSizeMake(MXKTOOLS_MEDIUM_IMAGE_SIZE, MXKTOOLS_MEDIUM_IMAGE_SIZE)];
}
else if (self.imageCompressionMode == ImageCompressionModeLarge)
{
image = [MXKTools reduceImage:image toFitInSize:CGSizeMake(self.actualLargeSize, self.actualLargeSize)];
}
// Make sure the uploaded image orientation is up
image = [MXKTools forceImageOrientationUp:image];
NSString *mimeType;
if ([itemProvider hasItemConformingToTypeIdentifier:(__bridge NSString *)kUTTypePNG])
{
mimeType = @"image/png";
imageData = UIImagePNGRepresentation(image);
}
else
{
// Use jpeg format by default.
mimeType = @"image/jpeg";
imageData = UIImageJPEGRepresentation(image, 0.9);
}
UIImage *thumbnail = nil;
// Thumbnail is useful only in case of encrypted room
if (room.state.isEncrypted)
{
thumbnail = [MXKTools reduceImage:image toFitInSize:CGSizeMake(800, 600)];
if (thumbnail == image)
// Prepare the image
NSData *convertedImageData;
if (self.imageCompressionMode == ImageCompressionModeSmall)
{
thumbnail = nil;
image = [MXKTools reduceImage:image toFitInSize:CGSizeMake(MXKTOOLS_SMALL_IMAGE_SIZE, MXKTOOLS_SMALL_IMAGE_SIZE)];
}
else if (self.imageCompressionMode == ImageCompressionModeMedium)
{
image = [MXKTools reduceImage:image toFitInSize:CGSizeMake(MXKTOOLS_MEDIUM_IMAGE_SIZE, MXKTOOLS_MEDIUM_IMAGE_SIZE)];
}
else if (self.imageCompressionMode == ImageCompressionModeLarge)
{
image = [MXKTools reduceImage:image toFitInSize:CGSizeMake(self.actualLargeSize, self.actualLargeSize)];
}
// Make sure the uploaded image orientation is up
image = [MXKTools forceImageOrientationUp:image];
NSString *mimeType;
if ([itemProvider hasItemConformingToTypeIdentifier:(__bridge NSString *)kUTTypePNG])
{
mimeType = @"image/png";
convertedImageData = UIImagePNGRepresentation(image);
}
else
{
// Use jpeg format by default.
mimeType = @"image/jpeg";
convertedImageData = UIImageJPEGRepresentation(image, 0.9);
}
UIImage *thumbnail = nil;
// Thumbnail is useful only in case of encrypted room
if (room.state.isEncrypted)
{
thumbnail = [MXKTools reduceImage:image toFitInSize:CGSizeMake(800, 600)];
if (thumbnail == image)
{
thumbnail = nil;
}
}
__weak typeof(self) weakSelf = self;
[room sendImage:convertedImageData withImageSize:image.size mimeType:mimeType andThumbnail:thumbnail localEcho:nil success:^(NSString *eventId) {
if (weakSelf)
{
typeof(self) self = weakSelf;
[imageDatas removeObject:imageData];
if (!imageDatas.count)
{
[self.shareExtensionContext completeRequestReturningItems:@[extensionItem] completionHandler:nil];
}
}
} failure:^(NSError *error) {
NSLog(@"[ShareExtensionManager] sendImage failed.");
[imageDatas removeObject:imageData];
if (!imageDatas.count)
{
if (failureBlock)
{
failureBlock(error);
}
}
}];
}
__weak typeof(self) weakSelf = self;
[room sendImage:imageData withImageSize:image.size mimeType:mimeType andThumbnail:thumbnail localEcho:nil success:^(NSString *eventId) {
if (weakSelf)
{
typeof(self) self = weakSelf;
[self completeRequestReturningItems:@[extensionItem] completionHandler:nil];
}
} failure:^(NSError *error) {
NSLog(@"[ShareExtensionManager] sendImage failed.");
if (failureBlock)
{
failureBlock();
}
}];
}
- (void)sendVideo:(NSURL *)videoLocalUrl toRoom:(MXRoom *)room extensionItem:(NSExtensionItem *)extensionItem failureBlock:(void(^)())failureBlock
- (void)sendVideo:(NSURL *)videoLocalUrl toRoom:(MXRoom *)room extensionItem:(NSExtensionItem *)extensionItem failureBlock:(void(^)(NSError *error))failureBlock
{
[self didStartSendingToRoom:room];
if (!videoLocalUrl)
@ -629,7 +672,7 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode)
NSLog(@"[ShareExtensionManager] loadItemForTypeIdentifier: failed.");
if (failureBlock)
{
failureBlock();
failureBlock(nil);
}
return;
}
@ -656,10 +699,27 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode)
NSLog(@"[ShareExtensionManager] sendVideo failed.");
if (failureBlock)
{
failureBlock();
failureBlock(error);
}
}];
}
@end
@implementation NSItemProvider (ShareExtensionManager)
- (void)setIsLoaded:(BOOL)isLoaded
{
NSNumber *number = [NSNumber numberWithBool:isLoaded];
objc_setAssociatedObject(self, @selector(isLoaded), number, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (BOOL)isLoaded
{
NSNumber *number = objc_getAssociatedObject(self, @selector(isLoaded));
return number.boolValue;
}
@end

View file

@ -1,144 +0,0 @@
/*
Copyright 2017 Aram Sargsyan
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 "ShareRecentsDataSource.h"
#import "RoomTableViewCell.h"
#import "RecentCellData.h"
@interface ShareRecentsDataSource ()
@property (nonatomic, readwrite) ShareRecentsDataSourceMode dataSourceMode;
@property NSMutableArray *recentRooms;
@property NSMutableArray *recentPeople;
@end
@implementation ShareRecentsDataSource
- (instancetype)initWithMatrixSession:(MXSession *)mxSession dataSourceMode:(ShareRecentsDataSourceMode)dataSourceMode
{
self = [super initWithMatrixSession:mxSession];
if (self)
{
self.dataSourceMode = dataSourceMode;
_recentRooms = [NSMutableArray array];
_recentPeople = [NSMutableArray array];
}
return self;
}
#pragma mark - Private
- (void)updateArrays
{
[self.recentPeople removeAllObjects];
[self.recentRooms removeAllObjects];
MXKSessionRecentsDataSource *recentsDataSource = displayedRecentsDataSourceArray.firstObject;
NSInteger count = recentsDataSource.numberOfCells;
for (int index = 0; index < count; index++)
{
id<MXKRecentCellDataStoring> cellData = [recentsDataSource cellDataAtIndex:index];
MXRoom* room = cellData.roomSummary.room;
if (self.dataSourceMode == RecentsDataSourceModePeople)
{
if (room.isDirect && room.state.membership == MXMembershipJoin)
{
[self.recentPeople addObject:cellData];
}
}
else if (self.dataSourceMode == RecentsDataSourceModeRooms)
{
if (!room.isDirect && room.state.membership == MXMembershipJoin)
{
[self.recentRooms addObject:cellData];
}
}
}
}
#pragma mark - MXKRecentsDataSource
- (Class)cellDataClassForCellIdentifier:(NSString *)identifier
{
return RecentCellData.class;
}
- (id<MXKRecentCellDataStoring>)cellDataAtIndexPath:(NSIndexPath *)indexPath
{
id<MXKRecentCellDataStoring> cellData = nil;
if (self.dataSourceMode == RecentsDataSourceModePeople)
{
cellData = self.recentPeople[indexPath.row];
}
else
{
cellData = self.recentRooms[indexPath.row];
}
return cellData;
}
- (void)dataSource:(MXKDataSource*)dataSource didCellChange:(id)changes
{
[super dataSource:dataSource didCellChange:changes];
[self updateArrays];
[self.delegate dataSource:self didCellChange:changes];
}
#pragma mark - UITableViewDataSource
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (self.dataSourceMode == RecentsDataSourceModePeople)
{
return self.recentPeople.count;
}
else
{
return self.recentRooms.count;
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
RoomTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:[RoomTableViewCell defaultReuseIdentifier]];
MXRoom *room = [self cellDataAtIndexPath:indexPath].roomSummary.room;
[cell render:room];
if (!room.summary.displayname.length && !cell.titleLabel.text.length)
{
cell.titleLabel.text = NSLocalizedStringFromTable(@"room_displayname_no_title", @"Vector", nil);
}
return cell;
}
@end

View file

@ -30,7 +30,7 @@
[super viewDidLoad];
self.titleLabel.textColor = kRiotSecondaryTextColor;
self.titleLabel.text = NSLocalizedStringFromTable(@"auth_share_extension_prompt", @"Vector", nil);
self.titleLabel.text = NSLocalizedStringFromTable(@"share_extension_auth_prompt", @"Vector", nil);
}
- (void)didReceiveMemoryWarning

View file

@ -16,7 +16,7 @@
#import <UIKit/UIKit.h>
#import "MXRoom+Riot.h"
#import "ShareRecentsDataSource.h"
#import "ShareDataSource.h"
@interface RoomsListViewController : MXKRecentListViewController

View file

@ -15,7 +15,7 @@
*/
#import "RoomsListViewController.h"
#import "RoomTableViewCell.h"
#import "RecentRoomTableViewCell.h"
#import "NSBundle+MatrixKit.h"
#import "ShareExtensionManager.h"
#import "RecentCellData.h"
@ -23,8 +23,6 @@
#import "MXKPieChartView.h"
#import "MXKPieChartHUD.h"
@interface RoomsListViewController () <ShareExtensionManagerDelegate>
@property (nonatomic) MXKPieChartHUD *hudView;
@ -35,7 +33,6 @@
@end
@implementation RoomsListViewController
#pragma mark - Class methods
@ -73,7 +70,7 @@
{
[super viewDidLoad];
[self.recentsTableView registerNib:[RoomTableViewCell nib] forCellReuseIdentifier:[RoomTableViewCell defaultReuseIdentifier]];
[self.recentsTableView registerNib:[RecentRoomTableViewCell nib] forCellReuseIdentifier:[RecentRoomTableViewCell defaultReuseIdentifier]];
[self configureSearchBar];
}
@ -130,35 +127,78 @@
- (void)showShareAlertForRoomPath:(NSIndexPath *)indexPath
{
// @TODO: the room should be instanciated here (only the room summary should be available from dataSource).
NSString *receipantName = [self.dataSource getRoomAtIndexPath:indexPath].summary.displayname;
if (!receipantName.length)
MXKRecentCellData *recentCellData = [self.dataSource cellDataAtIndexPath:indexPath];
NSString *roomName = recentCellData.roomSummary.displayname;
if (!roomName.length)
{
receipantName = NSLocalizedStringFromTable(@"room_displayname_no_title", @"Vector", nil);
roomName = NSLocalizedStringFromTable(@"room_displayname_no_title", @"Vector", nil);
}
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:[NSString stringWithFormat:NSLocalizedStringFromTable(@"send_to", @"Vector", nil), receipantName] message:nil preferredStyle:UIAlertControllerStyleAlert];
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:[NSString stringWithFormat:NSLocalizedStringFromTable(@"send_to", @"Vector", nil), roomName] message:nil preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:[NSBundle mxk_localizedStringForKey:@"cancel"] style:UIAlertActionStyleCancel handler:nil];
[alertController addAction:cancelAction];
UIAlertAction *sendAction = [UIAlertAction actionWithTitle:[NSBundle mxk_localizedStringForKey:@"send"] style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
MXRoom *selectedRoom = [self.dataSource getRoomAtIndexPath:indexPath];
[ShareExtensionManager sharedManager].delegate = self;
[[ShareExtensionManager sharedManager] sendContentToRoom:selectedRoom failureBlock:^{
[self showFailureAlert];
// The selected room is instanciated here.
[[ShareExtensionManager sharedManager].fileStore asyncAccountDataOfRoom:recentCellData.roomSummary.roomId success:^(MXRoomAccountData * _Nonnull accountData) {
[[ShareExtensionManager sharedManager].fileStore asyncStateEventsOfRoom:recentCellData.roomSummary.roomId success:^(NSArray<MXEvent *> * _Nonnull roomStateEvents) {
MXSession *session = [[MXSession alloc] initWithMatrixRestClient:[[MXRestClient alloc] initWithCredentials:[ShareExtensionManager sharedManager].userAccount.mxCredentials andOnUnrecognizedCertificateBlock:nil]];
// To handle correctly the crypto, we have to set a store (use a fake store)
__weak MXSession *weakSession = session;
[session setStore:[[MXNoStore alloc] init] success:^{
if (weakSession)
{
__strong MXSession *session = weakSession;
MXRoom *selectedRoom = [[MXRoom alloc] initWithRoomId:recentCellData.roomSummary.roomId andMatrixSession:session andStateEvents:roomStateEvents andAccountData:accountData];
[ShareExtensionManager sharedManager].delegate = self;
[[ShareExtensionManager sharedManager] sendContentToRoom:selectedRoom failureBlock:^(NSError* error) {
NSString *title;
if ([error.domain isEqualToString:MXEncryptingErrorDomain])
{
title = NSLocalizedStringFromTable(@"share_extension_failed_to_encrypt", @"Vector", nil);
}
[self showFailureAlert:title];
}];
}
} failure:^(NSError *error) {
NSLog(@"[RoomsListViewController] failed to prepare matrix session]");
}];
} failure:^(NSError * _Nonnull error) {
NSLog(@"[RoomsListViewController] failed to get state events");
}];
} failure:^(NSError * _Nonnull error) {
NSLog(@"[RoomsListViewController] failed to get account data");
}];
}];
[alertController addAction:sendAction];
[self presentViewController:alertController animated:YES completion:nil];
}
- (void)showFailureAlert
- (void)showFailureAlert:(NSString *)title
{
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:NSLocalizedStringFromTable(@"room_event_failed_to_send", @"Vector", nil) message:nil preferredStyle:UIAlertControllerStyleAlert];
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:title.length ? title : NSLocalizedStringFromTable(@"room_event_failed_to_send", @"Vector", nil) message:nil preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *okAction = [UIAlertAction actionWithTitle:[NSBundle mxk_localizedStringForKey:@"ok"] style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
if (self.failureBlock)
{
@ -173,7 +213,7 @@
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return [RoomTableViewCell cellHeight];
return [RecentRoomTableViewCell cellHeight];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
@ -189,7 +229,7 @@
{
if ([cellData isKindOfClass:[RecentCellData class]])
{
return [RoomTableViewCell class];
return [RecentRoomTableViewCell class];
}
return nil;
}
@ -198,13 +238,23 @@
{
if ([cellData isKindOfClass:[MXKRecentCellData class]])
{
return [RoomTableViewCell defaultReuseIdentifier];
return [RecentRoomTableViewCell defaultReuseIdentifier];
}
return nil;
}
#pragma mark - UISearchBarDelegate
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
NSArray *patterns = nil;
if (searchText.length)
{
patterns = @[searchText];
}
[self.dataSource searchWithPatterns:patterns];
}
- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar
{
if (searchBar == _tableSearchBar)
@ -229,6 +279,7 @@
- (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar
{
[self.recentsSearchBar setShowsCancelButton:NO animated:NO];
[self.dataSource searchWithPatterns:nil];
}
#pragma mark - UIScrollViewDelegate
@ -241,7 +292,7 @@
{
if (!self.recentsSearchBar.isHidden)
{
if (!self.recentsSearchBar.text.length && (scrollView.contentOffset.y + scrollView.contentInset.top > self.recentsSearchBar.frame.size.height))
if (!self.recentsSearchBar.text.length && (scrollView.contentOffset.y + scrollView.mxk_adjustedContentInset.top > self.recentsSearchBar.frame.size.height))
{
// Hide the search bar
[self hideSearchBar:YES];
@ -264,9 +315,12 @@
- (void)shareExtensionManager:(ShareExtensionManager *)extensionManager didStartSendingContentToRoom:(MXRoom *)room
{
self.parentViewController.view.userInteractionEnabled = NO;
self.hudView = [MXKPieChartHUD showLoadingHudOnView:self.view WithMessage:NSLocalizedStringFromTable(@"sending", @"Vector", nil)];
[self.hudView setProgress:0.0];
if (!self.hudView)
{
self.parentViewController.view.userInteractionEnabled = NO;
self.hudView = [MXKPieChartHUD showLoadingHudOnView:self.view WithMessage:NSLocalizedStringFromTable(@"sending", @"Vector", nil)];
[self.hudView setProgress:0.0];
}
}
- (void)shareExtensionManager:(ShareExtensionManager *)extensionManager mediaUploadProgress:(CGFloat)progress

View file

@ -18,7 +18,7 @@
#import "SegmentedViewController.h"
#import "RoomsListViewController.h"
#import "FallbackViewController.h"
#import "ShareRecentsDataSource.h"
#import "ShareDataSource.h"
#import "ShareExtensionManager.h"
@ -30,7 +30,7 @@
@property (nonatomic) SegmentedViewController *segmentedViewController;
@property (nonatomic) id shareExtensionManagerDidChangeMXSessionObserver;
@property (nonatomic) id shareExtensionManagerDidUpdateAccountDataObserver;
@end
@ -44,10 +44,10 @@
{
[super viewDidLoad];
self.shareExtensionManagerDidChangeMXSessionObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kShareExtensionManagerDidChangeMXSessionNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
self.shareExtensionManagerDidUpdateAccountDataObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kShareExtensionManagerDidUpdateAccountDataNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
[self configureViews];
}];
[self configureViews];
@ -57,10 +57,10 @@
{
[super destroy];
if (self.shareExtensionManagerDidChangeMXSessionObserver)
if (self.shareExtensionManagerDidUpdateAccountDataObserver)
{
[[NSNotificationCenter defaultCenter] removeObserver:self.shareExtensionManagerDidChangeMXSessionObserver];
self.shareExtensionManagerDidChangeMXSessionObserver = nil;
[[NSNotificationCenter defaultCenter] removeObserver:self.shareExtensionManagerDidUpdateAccountDataObserver];
self.shareExtensionManagerDidUpdateAccountDataObserver = nil;
}
[self resetContentView];
@ -94,7 +94,7 @@
[self resetContentView];
if ([ShareExtensionManager sharedManager].mxSession)
if ([ShareExtensionManager sharedManager].userAccount)
{
self.tittleLabel.text = [NSString stringWithFormat:NSLocalizedStringFromTable(@"send_to", @"Vector", nil), @""];
[self configureSegmentedViewController];
@ -120,12 +120,12 @@
}];
};
ShareRecentsDataSource *roomsDataSource = [[ShareRecentsDataSource alloc] initWithMatrixSession:[ShareExtensionManager sharedManager].mxSession dataSourceMode:RecentsDataSourceModeRooms];
ShareDataSource *roomsDataSource = [[ShareDataSource alloc] initWithMode:DataSourceModeRooms];
RoomsListViewController *roomsViewController = [RoomsListViewController recentListViewController];
roomsViewController.failureBlock = failureBlock;
[roomsViewController displayList:roomsDataSource];
ShareRecentsDataSource *peopleDataSource = [[ShareRecentsDataSource alloc] initWithMatrixSession:[ShareExtensionManager sharedManager].mxSession dataSourceMode:RecentsDataSourceModePeople];
ShareDataSource *peopleDataSource = [[ShareDataSource alloc] initWithMode:DataSourceModePeople];
RoomsListViewController *peopleViewController = [RoomsListViewController recentListViewController];
peopleViewController.failureBlock = failureBlock;
[peopleViewController displayList:peopleDataSource];

View file

@ -16,14 +16,8 @@
#import <MatrixKit/MatrixKit.h>
typedef NS_ENUM(NSInteger, ShareRecentsDataSourceMode)
{
RecentsDataSourceModePeople,
RecentsDataSourceModeRooms
};
@interface RecentRoomTableViewCell : MXKRecentTableViewCell
@interface ShareRecentsDataSource : MXKRecentsDataSource
- (instancetype)initWithMatrixSession:(MXSession *)mxSession dataSourceMode:(ShareRecentsDataSourceMode)dataSourceMode;
+ (CGFloat)cellHeight;
@end

View file

@ -0,0 +1,83 @@
/*
Copyright 2017 Aram Sargsyan
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 "RecentRoomTableViewCell.h"
#import "MXRoomSummary+Riot.h"
@interface RecentRoomTableViewCell ()
@property (weak, nonatomic) IBOutlet MXKImageView *avatarImageView;
@property (weak, nonatomic) IBOutlet UIView *directRoomBorderView;
@property (weak, nonatomic) IBOutlet UILabel *roomTitleLabel;
@property (weak, nonatomic) IBOutlet UIImageView *encryptedRoomIcon;
@end
@implementation RecentRoomTableViewCell
#pragma mark - MXKRecentTableViewCell
+ (UINib *)nib
{
// Check whether a nib file is available
NSBundle *mainBundle = [NSBundle bundleForClass:self.class];
NSString *path = [mainBundle pathForResource:NSStringFromClass([self class]) ofType:@"nib"];
if (path)
{
return [UINib nibWithNibName:NSStringFromClass([self class]) bundle:mainBundle];
}
return nil;
}
- (void)layoutSubviews
{
[super layoutSubviews];
// Round room avatars
[self.avatarImageView.layer setCornerRadius:self.avatarImageView.frame.size.width / 2];
self.avatarImageView.clipsToBounds = YES;
}
- (void)render:(MXKCellData *)cellData
{
// Sanity check: accept only object of MXKRecentCellData classes or sub-classes
NSParameterAssert([cellData isKindOfClass:[MXKRecentCellData class]]);
roomCellData = (id<MXKRecentCellDataStoring>)cellData;
if (roomCellData)
{
[roomCellData.roomSummary setRoomAvatarImageIn:self.avatarImageView];
self.roomTitleLabel.text = roomCellData.roomSummary.displayname;
if (!self.roomTitleLabel.text.length)
{
self.roomTitleLabel.text = NSLocalizedStringFromTable(@"room_displayname_no_title", @"Vector", nil);
}
self.directRoomBorderView.hidden = !roomCellData.roomSummary.isDirect;
self.encryptedRoomIcon.hidden = !roomCellData.roomSummary.isEncrypted;
}
}
+ (CGFloat)cellHeight
{
return 74;
}
@end

View file

@ -0,0 +1,85 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="13196" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13173"/>
<capability name="Aspect ratio constraints" minToolsVersion="5.1"/>
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<tableViewCell contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="3kk-d5-Wja" customClass="RecentRoomTableViewCell">
<rect key="frame" x="0.0" y="0.0" width="600" height="74"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="3kk-d5-Wja" id="b83-aU-AJ3">
<rect key="frame" x="0.0" y="0.0" width="600" height="73.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="HJd-Am-cCx" customClass="MXKImageView">
<rect key="frame" x="14" y="16" width="42" height="42"/>
<color key="backgroundColor" red="0.93725490199999995" green="0.93725490199999995" blue="0.95686274510000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<accessibility key="accessibilityConfiguration" identifier="AvatarImageView"/>
<constraints>
<constraint firstAttribute="width" secondItem="HJd-Am-cCx" secondAttribute="height" multiplier="1:1" id="CVW-Lp-6O4"/>
<constraint firstAttribute="width" constant="42" id="Xp0-5S-1wI"/>
</constraints>
</view>
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Fbf-fG-GSb">
<rect key="frame" x="14" y="16" width="42" height="42"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstAttribute="width" secondItem="Fbf-fG-GSb" secondAttribute="height" multiplier="1:1" id="1gX-EI-Ffa"/>
</constraints>
</view>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" text="Title" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="vBS-iO-8H6">
<rect key="frame" x="70" y="27" width="34" height="20"/>
<accessibility key="accessibilityConfiguration" identifier="TitleLabel"/>
<constraints>
<constraint firstAttribute="height" constant="20" id="H21-1K-fGz"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="e2e_verified.png" translatesAutoresizingMaskIntoConstraints="NO" id="hqD-YY-LWz">
<rect key="frame" x="50" y="42" width="11" height="13"/>
<accessibility key="accessibilityConfiguration" identifier="EncryptedRoomIcon"/>
<constraints>
<constraint firstAttribute="height" constant="13" id="8jQ-rK-hf2"/>
<constraint firstAttribute="width" constant="11" id="Mai-xD-TqV"/>
</constraints>
</imageView>
</subviews>
<constraints>
<constraint firstItem="HJd-Am-cCx" firstAttribute="leading" secondItem="b83-aU-AJ3" secondAttribute="leadingMargin" constant="6" id="4df-2f-865"/>
<constraint firstItem="hqD-YY-LWz" firstAttribute="top" secondItem="b83-aU-AJ3" secondAttribute="topMargin" constant="34" id="Cdm-v3-js8"/>
<constraint firstItem="Fbf-fG-GSb" firstAttribute="width" secondItem="HJd-Am-cCx" secondAttribute="width" id="RBA-bw-MFn"/>
<constraint firstItem="hqD-YY-LWz" firstAttribute="leading" secondItem="b83-aU-AJ3" secondAttribute="leadingMargin" constant="42" id="UIE-13-LGw"/>
<constraint firstItem="Fbf-fG-GSb" firstAttribute="centerY" secondItem="HJd-Am-cCx" secondAttribute="centerY" id="Xxe-pe-r6t"/>
<constraint firstItem="HJd-Am-cCx" firstAttribute="centerY" secondItem="b83-aU-AJ3" secondAttribute="centerY" id="flh-LO-k3n"/>
<constraint firstItem="Fbf-fG-GSb" firstAttribute="centerX" secondItem="HJd-Am-cCx" secondAttribute="centerX" id="oKN-d4-vd0"/>
<constraint firstItem="vBS-iO-8H6" firstAttribute="centerY" secondItem="b83-aU-AJ3" secondAttribute="centerY" id="ocY-mt-0n0"/>
<constraint firstAttribute="trailingMargin" relation="greaterThanOrEqual" secondItem="vBS-iO-8H6" secondAttribute="trailing" constant="15" id="qqy-zs-Ccy"/>
<constraint firstItem="vBS-iO-8H6" firstAttribute="leading" secondItem="HJd-Am-cCx" secondAttribute="trailing" constant="14" id="quv-47-R9n"/>
</constraints>
</tableViewCellContentView>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<accessibility key="accessibilityConfiguration" identifier="RoomTableViewCell"/>
<connections>
<outlet property="avatarImageView" destination="HJd-Am-cCx" id="Mv2-Kb-aG4"/>
<outlet property="directRoomBorderView" destination="Fbf-fG-GSb" id="aid-IX-joJ"/>
<outlet property="encryptedRoomIcon" destination="hqD-YY-LWz" id="Ikp-Sf-Vlc"/>
<outlet property="roomTitleLabel" destination="vBS-iO-8H6" id="0J9-p3-Lzx"/>
</connections>
<point key="canvasLocation" x="-53" y="-43"/>
</tableViewCell>
</objects>
<resources>
<image name="e2e_verified.png" width="10" height="12"/>
</resources>
</document>