mirror of
https://github.com/vector-im/element-ios.git
synced 2024-09-28 23:32:41 +00:00
Merge branch 'master' into callkit
# Conflicts: # Riot.xcodeproj/project.pbxproj # Riot/AppDelegate.m # Riot/ViewController/SettingsViewController.m
This commit is contained in:
commit
7801cabe32
74 changed files with 2169 additions and 889 deletions
|
@ -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
|
||||
|
45
CHANGES.rst
45
CHANGES.rst
|
@ -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
14
Podfile
|
@ -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'
|
||||
|
|
56
Podfile.lock
56
Podfile.lock
|
@ -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
|
||||
|
|
|
@ -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 = (
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.";
|
||||
|
|
|
@ -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";
|
||||
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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.";
|
||||
|
|
|
@ -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 %@ : '%@'";
|
||||
|
|
|
@ -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 n’avez 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 d’inviter 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.";
|
||||
|
|
|
@ -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";
|
||||
|
|
5
Riot/Assets/ru.lproj/InfoPlist.strings
Normal file
5
Riot/Assets/ru.lproj/InfoPlist.strings
Normal file
|
@ -0,0 +1,5 @@
|
|||
// Permissions usage explanations
|
||||
"NSCameraUsageDescription" = "Камера используется для съемки фотографий и видеороликов, а также для видеозвонков.";
|
||||
"NSPhotoLibraryUsageDescription" = "Галерея используется для отправки фотографий и видео.";
|
||||
"NSMicrophoneUsageDescription" = "Микрофон используется при съемке видео и выполнении звонков.";
|
||||
"NSContactsUsageDescription" = "Контакты используются для поиска пользователей в Riot по электронной почте или номеру телефона.";
|
|
@ -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 */
|
||||
|
|
|
@ -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" = "Комната %@ не видна.";
|
||||
|
|
|
@ -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" = "关闭";
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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" : {
|
||||
|
|
BIN
Riot/Images.xcassets/AppIcon.appiconset/Icon-1024.png
Normal file
BIN
Riot/Images.xcassets/AppIcon.appiconset/Icon-1024.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 40 KiB |
BIN
Riot/Images.xcassets/AppIcon.appiconset/Icon-20.png
Normal file
BIN
Riot/Images.xcassets/AppIcon.appiconset/Icon-20.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
BIN
Riot/Images.xcassets/AppIcon.appiconset/Icon-20@2x-1.png
Normal file
BIN
Riot/Images.xcassets/AppIcon.appiconset/Icon-20@2x-1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
BIN
Riot/Images.xcassets/AppIcon.appiconset/Icon-20@2x.png
Normal file
BIN
Riot/Images.xcassets/AppIcon.appiconset/Icon-20@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
BIN
Riot/Images.xcassets/AppIcon.appiconset/Icon-20@3x.png
Normal file
BIN
Riot/Images.xcassets/AppIcon.appiconset/Icon-20@3x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.7 KiB |
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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"])
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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];
|
||||
|
||||
}];
|
||||
|
||||
|
|
|
@ -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];
|
||||
|
||||
}];
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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];
|
||||
|
||||
}];
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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];
|
||||
|
||||
}];
|
||||
}
|
||||
|
|
|
@ -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];
|
||||
|
||||
}];
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
}];
|
||||
}
|
||||
}];
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
56
Riot/ViewController/Widgets/WidgetPickerViewController.h
Normal file
56
Riot/ViewController/Widgets/WidgetPickerViewController.h
Normal 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
|
99
Riot/ViewController/Widgets/WidgetPickerViewController.m
Normal file
99
Riot/ViewController/Widgets/WidgetPickerViewController.m
Normal 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
|
|
@ -20,6 +20,8 @@
|
|||
|
||||
- (void)prepareForReuse
|
||||
{
|
||||
[super prepareForReuse];
|
||||
|
||||
if (self.heightConstraint != 0)
|
||||
{
|
||||
self.heightConstraint = 0;
|
||||
|
|
|
@ -45,6 +45,8 @@
|
|||
|
||||
- (void)prepareForReuse
|
||||
{
|
||||
[super prepareForReuse];
|
||||
|
||||
if (self.pictureViewTopConstraint.constant != xibPictureViewTopConstraintConstant)
|
||||
{
|
||||
self.pictureViewTopConstraint.constant = xibPictureViewTopConstraintConstant;
|
||||
|
|
|
@ -45,6 +45,8 @@
|
|||
|
||||
- (void)prepareForReuse
|
||||
{
|
||||
[super prepareForReuse];
|
||||
|
||||
// Reset avatars
|
||||
for (UIView *avatarView in self.avatarsView.subviews)
|
||||
{
|
||||
|
|
41
Riot/Views/RoomInputToolbar/KeyboardGrowingTextView.m
Normal file
41
Riot/Views/RoomInputToolbar/KeyboardGrowingTextView.m
Normal 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
|
|
@ -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"/>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
38
RiotShareExtension/Model/ShareDataSource.h
Normal file
38
RiotShareExtension/Model/ShareDataSource.h
Normal 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
|
174
RiotShareExtension/Model/ShareDataSource.m
Normal file
174
RiotShareExtension/Model/ShareDataSource.m
Normal 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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "MXRoom+Riot.h"
|
||||
#import "ShareRecentsDataSource.h"
|
||||
#import "ShareDataSource.h"
|
||||
|
||||
@interface RoomsListViewController : MXKRecentListViewController
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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
|
83
RiotShareExtension/Views/RecentRoomTableViewCell.m
Normal file
83
RiotShareExtension/Views/RecentRoomTableViewCell.m
Normal 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
|
85
RiotShareExtension/Views/RecentRoomTableViewCell.xib
Normal file
85
RiotShareExtension/Views/RecentRoomTableViewCell.xib
Normal 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>
|
Loading…
Reference in a new issue