mirror of
https://github.com/vector-im/element-ios.git
synced 2024-09-29 07:42:40 +00:00
Merge remote-tracking branch 'origin/develop' into develop
This commit is contained in:
commit
66685b2deb
57 changed files with 1756 additions and 691 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
|
||||
|
6
Podfile
6
Podfile
|
@ -22,7 +22,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'
|
||||
|
||||
|
@ -32,7 +32,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
|
||||
|
@ -50,7 +50,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'
|
||||
|
||||
# The tagged version on which this version of Riot share extension has been built
|
||||
pod 'MatrixKit/AppExtension', '0.6.2'
|
||||
|
|
10
Podfile.lock
10
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)
|
||||
|
@ -91,7 +91,7 @@ DEPENDENCIES:
|
|||
SPEC CHECKSUMS:
|
||||
AFNetworking: 5e0e199f73d8626b11e79750991f5d173d1f8b67
|
||||
cmark: ec0275215b504780287b6fca360224e384368af8
|
||||
DTCoreText: 51904f2374af443e0d270d6fdc76035ab6f9ef8a
|
||||
DTCoreText: e5d688cffc9f6a61eddd1a4f94e2046851230de3
|
||||
DTFoundation: 26a164ef510877387906fb92bff524a792db4bf8
|
||||
GBDeviceInfo: caae36532afcc209b51ac62bba547aadab9e88f2
|
||||
GoogleAnalytics: f42cc53a87a51fe94334821868d9c8481ff47a7b
|
||||
|
|
|
@ -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 */; };
|
||||
|
@ -27,7 +29,7 @@
|
|||
24EEE5A11F23A09A00B3C705 /* RiotDesignValues.m in Sources */ = {isa = PBXBuildFile; fileRef = F083BC171E7009EC00A9B29C /* RiotDesignValues.m */; };
|
||||
24EEE5A21F23A8B400B3C705 /* MXRoom+Riot.m in Sources */ = {isa = PBXBuildFile; fileRef = F083BBE81E7009EC00A9B29C /* MXRoom+Riot.m */; };
|
||||
24EEE5A31F23A8C300B3C705 /* AvatarGenerator.m in Sources */ = {isa = PBXBuildFile; fileRef = F083BC111E7009EC00A9B29C /* AvatarGenerator.m */; };
|
||||
24EEE5A41F24C06E00B3C705 /* (null) in Resources */ = {isa = PBXBuildFile; };
|
||||
24EEE5A41F24C06E00B3C705 /* BuildFile in Resources */ = {isa = PBXBuildFile; };
|
||||
24EEE5A81F25529600B3C705 /* cancel@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = F0614A121EDEE65000F5DC9A /* cancel@3x.png */; };
|
||||
24EEE5A91F25529900B3C705 /* cancel@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = F0614A111EDEE65000F5DC9A /* cancel@2x.png */; };
|
||||
24EEE5AA1F25529C00B3C705 /* cancel.png in Resources */ = {isa = PBXBuildFile; fileRef = F0614A101EDEE65000F5DC9A /* cancel.png */; };
|
||||
|
@ -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 */; };
|
||||
|
@ -81,6 +84,7 @@
|
|||
32F3AE1A1F6FF4E600F0F004 /* WidgetViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F3AE191F6FF4E600F0F004 /* WidgetViewController.m */; };
|
||||
32FD0A3D1EB0CD9B0072B066 /* BugReportViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 32FD0A3B1EB0CD9B0072B066 /* BugReportViewController.m */; };
|
||||
32FD0A3E1EB0CD9B0072B066 /* BugReportViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 32FD0A3C1EB0CD9B0072B066 /* BugReportViewController.xib */; };
|
||||
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 */; };
|
||||
A27ECCE3FC4971745D2CB78D /* libPods-RiotShareExtension.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7246451C668D6782166E22EC /* libPods-RiotShareExtension.a */; };
|
||||
|
@ -490,6 +494,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 */; };
|
||||
|
@ -578,6 +586,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; };
|
||||
|
@ -596,8 +607,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>"; };
|
||||
|
@ -649,6 +660,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>"; };
|
||||
|
@ -662,6 +675,7 @@
|
|||
32FD0A3C1EB0CD9B0072B066 /* BugReportViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = BugReportViewController.xib; sourceTree = "<group>"; };
|
||||
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>"; };
|
||||
|
@ -1275,12 +1289,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;
|
||||
|
@ -1311,8 +1337,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;
|
||||
|
@ -1349,6 +1375,8 @@
|
|||
3233F72E1F31F4BF006ACA81 /* JitsiViewController.h */,
|
||||
3233F72F1F31F4BF006ACA81 /* JitsiViewController.m */,
|
||||
3233F7301F31F4BF006ACA81 /* JitsiViewController.xib */,
|
||||
32C2356D1F7B871800E38FC5 /* WidgetPickerViewController.h */,
|
||||
32C2356E1F7B871800E38FC5 /* WidgetPickerViewController.m */,
|
||||
);
|
||||
path = Widgets;
|
||||
sourceTree = "<group>";
|
||||
|
@ -2201,6 +2229,7 @@
|
|||
F083BCD91E7009EC00A9B29C /* RoomInputToolbarView.h */,
|
||||
F083BCDA1E7009EC00A9B29C /* RoomInputToolbarView.m */,
|
||||
F083BCDB1E7009EC00A9B29C /* RoomInputToolbarView.xib */,
|
||||
83711A7B1F6F8E7D008F0D4D /* KeyboardGrowingTextView.m */,
|
||||
);
|
||||
path = RoomInputToolbar;
|
||||
sourceTree = "<group>";
|
||||
|
@ -2487,14 +2516,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 */,
|
||||
24EEE5A41F24C06E00B3C705 /* BuildFile in Resources */,
|
||||
2439DD641F6BBEA50090F42D /* RecentRoomTableViewCell.xib in Resources */,
|
||||
24EEE5A41F24C06E00B3C705 /* BuildFile in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -3025,7 +3059,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 */,
|
||||
|
@ -3034,6 +3068,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 */,
|
||||
);
|
||||
|
@ -3075,6 +3111,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 */,
|
||||
|
@ -3101,6 +3138,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 */,
|
||||
|
|
|
@ -516,6 +516,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];
|
||||
}
|
||||
|
|
|
@ -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";
|
||||
|
@ -340,8 +339,12 @@
|
|||
//"settings_call_invitations" = "Call invitations";
|
||||
|
||||
"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 %@?";
|
||||
|
||||
|
@ -456,6 +459,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 %@";
|
||||
|
||||
|
@ -525,3 +530,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";
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -417,8 +417,12 @@
|
|||
"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";
|
||||
"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";
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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,15 @@
|
|||
"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" = "Не удалось создать виджет";
|
||||
|
|
|
@ -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" = "关闭";
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
@ -2881,19 +2907,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 +3016,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 +3468,7 @@
|
|||
// Update the bar
|
||||
[self refreshActivitiesViewDisplay];
|
||||
[self refreshRoomInputToolbar];
|
||||
[self refreshRoomTitle];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
@ -3465,6 +3489,12 @@
|
|||
[[AppDelegate theDelegate] showErrorAsAlert:error];
|
||||
}
|
||||
|
||||
- (NSUInteger)widgetsCount
|
||||
{
|
||||
return [[WidgetManager sharedManager] widgetsNotOfTypes:@[kWidgetTypeJitsi]
|
||||
inRoom:self.roomDataSource.room].count;
|
||||
}
|
||||
|
||||
#pragma mark - Unreachable Network Handling
|
||||
|
||||
- (void)refreshActivitiesViewDisplay
|
||||
|
@ -3700,15 +3730,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 +3745,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 +4104,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 +4191,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
|
||||
|
||||
|
|
|
@ -40,6 +40,8 @@
|
|||
|
||||
#import "OLMKit/OLMKit.h"
|
||||
|
||||
#import "GBDeviceInfo_iOS.h"
|
||||
|
||||
|
||||
NSString* const kSettingsViewControllerPhoneBookCountryCellId = @"kSettingsViewControllerPhoneBookCountryCellId";
|
||||
|
||||
|
@ -205,9 +207,6 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)();
|
|||
BOOL keepNewEmailEditing;
|
||||
BOOL keepNewPhoneNumberEditing;
|
||||
|
||||
// The user interface theme cell
|
||||
TableViewCellWithCheckBoxes *uiThemeCell;
|
||||
|
||||
// The current pushed view controller
|
||||
UIViewController *pushedViewController;
|
||||
}
|
||||
|
@ -250,7 +249,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;
|
||||
|
@ -417,7 +415,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];
|
||||
|
||||
}];
|
||||
|
||||
|
@ -1695,36 +1693,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)
|
||||
|
@ -2270,6 +2271,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)
|
||||
{
|
||||
|
@ -3430,6 +3435,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
|
||||
|
@ -3769,25 +3858,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
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