mirror of
https://github.com/vector-im/element-ios.git
synced 2024-09-28 23:32:41 +00:00
Merge pull request #1447 from aramsargsyan/app-extension-improvements
App extension improvements
This commit is contained in:
commit
ee74daa1c4
19 changed files with 1564 additions and 35 deletions
2
Podfile
2
Podfile
|
@ -53,7 +53,7 @@ pod 'OLMKit'
|
|||
pod 'Realm', '~> 2.8.1'
|
||||
|
||||
# The tagged version on which this version of Riot has been built
|
||||
pod 'MatrixKit', '0.6.0'
|
||||
pod 'MatrixKit', '0.6.1'
|
||||
|
||||
# The lastest release available on the CocoaPods repository
|
||||
#pod 'MatrixKit/AppExtension'
|
||||
|
|
|
@ -8,18 +8,21 @@
|
|||
|
||||
/* Begin PBXBuildFile section */
|
||||
05D592A32FF1D1877B89F73C /* libPods-Riot.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FD9D0BDE9232898950554DD5 /* libPods-Riot.a */; };
|
||||
243517981F375B6800D0683E /* FallbackViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2466B7531F2F80B800AE27B0 /* FallbackViewController.m */; };
|
||||
243517991F375B7100D0683E /* FallbackViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2466B7541F2F80B800AE27B0 /* FallbackViewController.xib */; };
|
||||
2435179A1F375B8A00D0683E /* ShareViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2466B75C1F2F80B800AE27B0 /* ShareViewController.m */; };
|
||||
2435179B1F375B8F00D0683E /* SharePresentingViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2466B75A1F2F80B800AE27B0 /* SharePresentingViewController.m */; };
|
||||
2435179C1F375B9400D0683E /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 2466B7551F2F80B800AE27B0 /* Info.plist */; };
|
||||
2435179D1F375BA100D0683E /* ShareViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2466B75D1F2F80B800AE27B0 /* ShareViewController.xib */; };
|
||||
2435179E1F375BA600D0683E /* RoomsListViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2466B7581F2F80B800AE27B0 /* RoomsListViewController.m */; };
|
||||
2435179F1F375C0F00D0683E /* Vector.strings in Resources */ = {isa = PBXBuildFile; fileRef = 327382C01F276AED00356143 /* Vector.strings */; };
|
||||
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 */; };
|
||||
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 */; };
|
||||
24D6B35C1F3CA03600FC7A71 /* RoomsListViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 24D6B3491F3C8F8A00FC7A71 /* RoomsListViewController.m */; };
|
||||
24D6B35D1F3CA03A00FC7A71 /* FallbackViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 24D6B3461F3C8F8A00FC7A71 /* FallbackViewController.m */; };
|
||||
24D6B35E1F3CA03E00FC7A71 /* FallbackViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 24D6B3471F3C8F8A00FC7A71 /* FallbackViewController.xib */; };
|
||||
24EEE5A01F23A08900B3C705 /* RoomTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = F083BCED1E7009EC00A9B29C /* RoomTableViewCell.m */; };
|
||||
24EEE5A11F23A09A00B3C705 /* RiotDesignValues.m in Sources */ = {isa = PBXBuildFile; fileRef = F083BC171E7009EC00A9B29C /* RiotDesignValues.m */; };
|
||||
24EEE5A21F23A8B400B3C705 /* MXRoom+Riot.m in Sources */ = {isa = PBXBuildFile; fileRef = F083BBE81E7009EC00A9B29C /* MXRoom+Riot.m */; };
|
||||
|
@ -545,22 +548,26 @@
|
|||
|
||||
/* 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>"; };
|
||||
2466B7521F2F80B800AE27B0 /* FallbackViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FallbackViewController.h; path = RiotShareExtension/FallbackViewController.h; sourceTree = SOURCE_ROOT; };
|
||||
2466B7531F2F80B800AE27B0 /* FallbackViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = FallbackViewController.m; path = RiotShareExtension/FallbackViewController.m; sourceTree = SOURCE_ROOT; };
|
||||
2466B7541F2F80B800AE27B0 /* FallbackViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = FallbackViewController.xib; path = RiotShareExtension/FallbackViewController.xib; sourceTree = SOURCE_ROOT; };
|
||||
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; };
|
||||
2466B7561F2F80B800AE27B0 /* RiotShareExtension.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; name = RiotShareExtension.entitlements; path = RiotShareExtension/RiotShareExtension.entitlements; sourceTree = SOURCE_ROOT; };
|
||||
2466B7571F2F80B800AE27B0 /* RoomsListViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RoomsListViewController.h; path = RiotShareExtension/RoomsListViewController.h; sourceTree = SOURCE_ROOT; };
|
||||
2466B7581F2F80B800AE27B0 /* RoomsListViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RoomsListViewController.m; path = RiotShareExtension/RoomsListViewController.m; sourceTree = SOURCE_ROOT; };
|
||||
2466B7591F2F80B800AE27B0 /* SharePresentingViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SharePresentingViewController.h; path = RiotShareExtension/SharePresentingViewController.h; sourceTree = SOURCE_ROOT; };
|
||||
2466B75A1F2F80B800AE27B0 /* SharePresentingViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SharePresentingViewController.m; path = RiotShareExtension/SharePresentingViewController.m; sourceTree = SOURCE_ROOT; };
|
||||
2466B75B1F2F80B800AE27B0 /* ShareViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ShareViewController.h; path = RiotShareExtension/ShareViewController.h; sourceTree = SOURCE_ROOT; };
|
||||
2466B75C1F2F80B800AE27B0 /* ShareViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ShareViewController.m; path = RiotShareExtension/ShareViewController.m; sourceTree = SOURCE_ROOT; };
|
||||
2466B75D1F2F80B800AE27B0 /* ShareViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = ShareViewController.xib; path = RiotShareExtension/ShareViewController.xib; sourceTree = SOURCE_ROOT; };
|
||||
24B5103C1EFA7083004C6AD2 /* ReadReceiptsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ReadReceiptsViewController.h; sourceTree = "<group>"; };
|
||||
24B5103D1EFA7083004C6AD2 /* ReadReceiptsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ReadReceiptsViewController.m; sourceTree = "<group>"; };
|
||||
24B5103F1EFA88CC004C6AD2 /* ReadReceiptsViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ReadReceiptsViewController.xib; sourceTree = "<group>"; };
|
||||
24CBEC4E1F0EAD310093EABB /* RiotShareExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = RiotShareExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
24D6B3451F3C8F8A00FC7A71 /* FallbackViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FallbackViewController.h; sourceTree = "<group>"; };
|
||||
24D6B3461F3C8F8A00FC7A71 /* FallbackViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FallbackViewController.m; sourceTree = "<group>"; };
|
||||
24D6B3471F3C8F8A00FC7A71 /* FallbackViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = FallbackViewController.xib; sourceTree = "<group>"; };
|
||||
24D6B3481F3C8F8A00FC7A71 /* RoomsListViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RoomsListViewController.h; sourceTree = "<group>"; };
|
||||
24D6B3491F3C8F8A00FC7A71 /* RoomsListViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RoomsListViewController.m; sourceTree = "<group>"; };
|
||||
24D6B34A1F3C8F8A00FC7A71 /* SharePresentingViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SharePresentingViewController.h; sourceTree = "<group>"; };
|
||||
24D6B34B1F3C8F8A00FC7A71 /* SharePresentingViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SharePresentingViewController.m; sourceTree = "<group>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
|
@ -1216,21 +1223,43 @@
|
|||
children = (
|
||||
2466B7551F2F80B800AE27B0 /* Info.plist */,
|
||||
2466B7561F2F80B800AE27B0 /* RiotShareExtension.entitlements */,
|
||||
2466B7591F2F80B800AE27B0 /* SharePresentingViewController.h */,
|
||||
2466B75A1F2F80B800AE27B0 /* SharePresentingViewController.m */,
|
||||
2466B75B1F2F80B800AE27B0 /* ShareViewController.h */,
|
||||
2466B75C1F2F80B800AE27B0 /* ShareViewController.m */,
|
||||
2466B75D1F2F80B800AE27B0 /* ShareViewController.xib */,
|
||||
2466B7571F2F80B800AE27B0 /* RoomsListViewController.h */,
|
||||
2466B7581F2F80B800AE27B0 /* RoomsListViewController.m */,
|
||||
2466B7521F2F80B800AE27B0 /* FallbackViewController.h */,
|
||||
2466B7531F2F80B800AE27B0 /* FallbackViewController.m */,
|
||||
2466B7541F2F80B800AE27B0 /* FallbackViewController.xib */,
|
||||
24D6B3441F3C8F8A00FC7A71 /* ViewController */,
|
||||
24D6B3551F3C8FCC00FC7A71 /* Model */,
|
||||
);
|
||||
name = RiotShareExtension;
|
||||
path = "Riot Share Extension";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
24D6B3441F3C8F8A00FC7A71 /* ViewController */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
24D6B34A1F3C8F8A00FC7A71 /* SharePresentingViewController.h */,
|
||||
24D6B34B1F3C8F8A00FC7A71 /* SharePresentingViewController.m */,
|
||||
24D6B34C1F3C8F8A00FC7A71 /* ShareViewController.h */,
|
||||
24D6B34D1F3C8F8A00FC7A71 /* ShareViewController.m */,
|
||||
24D6B34E1F3C8F8A00FC7A71 /* ShareViewController.xib */,
|
||||
24D6B3481F3C8F8A00FC7A71 /* RoomsListViewController.h */,
|
||||
24D6B3491F3C8F8A00FC7A71 /* RoomsListViewController.m */,
|
||||
24D6B3451F3C8F8A00FC7A71 /* FallbackViewController.h */,
|
||||
24D6B3461F3C8F8A00FC7A71 /* FallbackViewController.m */,
|
||||
24D6B3471F3C8F8A00FC7A71 /* FallbackViewController.xib */,
|
||||
);
|
||||
name = ViewController;
|
||||
path = RiotShareExtension/ViewController;
|
||||
sourceTree = SOURCE_ROOT;
|
||||
};
|
||||
24D6B3551F3C8FCC00FC7A71 /* Model */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
245FC3EA1F3CAF9800603C6A /* ShareExtensionManager.h */,
|
||||
245FC3EB1F3CAF9800603C6A /* ShareExtensionManager.m */,
|
||||
24D6B3561F3C90D300FC7A71 /* ShareRecentsDataSource.h */,
|
||||
24D6B3571F3C90D300FC7A71 /* ShareRecentsDataSource.m */,
|
||||
);
|
||||
name = Model;
|
||||
path = RiotShareExtension/Model;
|
||||
sourceTree = SOURCE_ROOT;
|
||||
};
|
||||
3205ED801E97725E003D65FA /* Directory */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -2313,16 +2342,16 @@
|
|||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
2435179D1F375BA100D0683E /* ShareViewController.xib in Resources */,
|
||||
24D6B35B1F3CA03300FC7A71 /* ShareViewController.xib in Resources */,
|
||||
24EEE5B51F2607C500B3C705 /* SegmentedViewController.xib in Resources */,
|
||||
24EEE5A91F25529900B3C705 /* cancel@2x.png in Resources */,
|
||||
2435179C1F375B9400D0683E /* Info.plist in Resources */,
|
||||
243517991F375B7100D0683E /* FallbackViewController.xib in Resources */,
|
||||
24EEE5A81F25529600B3C705 /* cancel@3x.png in Resources */,
|
||||
2466B73E1F2DFAC100AE27B0 /* animatedLogo-4.png in Resources */,
|
||||
2435179F1F375C0F00D0683E /* Vector.strings in Resources */,
|
||||
24EEE5AF1F25F0F500B3C705 /* Images.xcassets in Resources */,
|
||||
24EEE5AA1F25529C00B3C705 /* cancel.png in Resources */,
|
||||
24D6B35E1F3CA03E00FC7A71 /* FallbackViewController.xib in Resources */,
|
||||
24EEE5A41F24C06E00B3C705 /* (null) in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
@ -2770,13 +2799,16 @@
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
24EEE5A01F23A08900B3C705 /* RoomTableViewCell.m in Sources */,
|
||||
24D6B3581F3C90D300FC7A71 /* ShareRecentsDataSource.m in Sources */,
|
||||
245FC3EF1F3DD30800603C6A /* RecentCellData.m in Sources */,
|
||||
24D6B35C1F3CA03600FC7A71 /* RoomsListViewController.m in Sources */,
|
||||
24D6B35A1F3CA02C00FC7A71 /* ShareViewController.m in Sources */,
|
||||
24D6B3591F3CA02900FC7A71 /* SharePresentingViewController.m in Sources */,
|
||||
24EEE5A31F23A8C300B3C705 /* AvatarGenerator.m in Sources */,
|
||||
2435179E1F375BA600D0683E /* RoomsListViewController.m in Sources */,
|
||||
243517981F375B6800D0683E /* FallbackViewController.m in Sources */,
|
||||
2435179B1F375B8F00D0683E /* SharePresentingViewController.m in Sources */,
|
||||
24D6B35D1F3CA03A00FC7A71 /* FallbackViewController.m in Sources */,
|
||||
24EEE5A11F23A09A00B3C705 /* RiotDesignValues.m in Sources */,
|
||||
2435179A1F375B8A00D0683E /* ShareViewController.m in Sources */,
|
||||
24EEE5A21F23A8B400B3C705 /* MXRoom+Riot.m in Sources */,
|
||||
245FC3ED1F3D079A00603C6A /* ShareExtensionManager.m in Sources */,
|
||||
24EEE5B41F2607C000B3C705 /* SegmentedViewController.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
"rename" = "Rename";
|
||||
"collapse" = "collapse";
|
||||
"send_to" = "Send to %@";
|
||||
"sending" = "Sending";
|
||||
|
||||
// Authentication
|
||||
"auth_login" = "Log in";
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
/**
|
||||
Update the information displayed by the cell.
|
||||
|
||||
@param rooom the room to render.
|
||||
@param room the room to render.
|
||||
*/
|
||||
- (void)render:(MXRoom *)room;
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
<key>NSExtensionActivationSupportsMovieWithMaxCount</key>
|
||||
<integer>1</integer>
|
||||
<key>NSExtensionActivationSupportsImageWithMaxCount</key>
|
||||
<integer>3</integer>
|
||||
<integer>1</integer>
|
||||
<key>NSExtensionActivationSupportsWebURLWithMaxCount</key>
|
||||
<integer>1</integer>
|
||||
<key>NSExtensionActivationSupportsText</key>
|
||||
|
|
89
RiotShareExtension/Model/ShareExtensionManager.h
Normal file
89
RiotShareExtension/Model/ShareExtensionManager.h
Normal file
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
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 <Foundation/Foundation.h>
|
||||
#import <MatrixKit/MatrixKit.h>
|
||||
|
||||
@class ShareExtensionManager;
|
||||
|
||||
/**
|
||||
The protocol for the manager's delegate
|
||||
*/
|
||||
@protocol ShareExtensionManagerDelegate <NSObject>
|
||||
|
||||
@required
|
||||
|
||||
/**
|
||||
Called when an image is going to be shared to show a compression prompt
|
||||
@param extensionManager the ShareExtensionManager object that called the method
|
||||
@param compressionPrompt the prompt that was prepared for the image which is going to be shared
|
||||
*/
|
||||
- (void)shareExtensionManager:(ShareExtensionManager *)extensionManager showImageCompressionPrompt:(UIAlertController *)compressionPrompt;
|
||||
|
||||
@optional
|
||||
|
||||
/**
|
||||
Called when the progress of the uploading media changes
|
||||
@param extensionManager the ShareExtensionManager object that called the method
|
||||
@param progress the current progress
|
||||
*/
|
||||
- (void)shareExtensionManager:(ShareExtensionManager *)extensionManager mediaUploadProgress:(CGFloat)progress;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
/**
|
||||
A class used to share content from the extension
|
||||
*/
|
||||
|
||||
@interface ShareExtensionManager : NSObject
|
||||
|
||||
/**
|
||||
The share extension context that represents a user's sharing request, also stores the content to be shared
|
||||
*/
|
||||
@property (nonatomic) NSExtensionContext *shareExtensionContext;
|
||||
|
||||
/**
|
||||
A delegate used to notify about needed UI changes when sharing
|
||||
*/
|
||||
@property (nonatomic) id<ShareExtensionManagerDelegate> delegate;
|
||||
|
||||
/**
|
||||
The singleton instance
|
||||
*/
|
||||
+ (instancetype)sharedManager;
|
||||
|
||||
/**
|
||||
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
|
||||
*/
|
||||
- (void)sendContentToRoom:(MXRoom *)room failureBlock:(void(^)())failureBlock;
|
||||
|
||||
/**
|
||||
Checks if there is an image in the user chosen content
|
||||
@return YES if there is, NO otherwise
|
||||
*/
|
||||
- (BOOL)hasImageTypeContent;
|
||||
|
||||
/**
|
||||
Terminate the extension and return to the app that started it
|
||||
@param canceled YES if the user chose to cancel the sharing, NO otherwise
|
||||
*/
|
||||
- (void)terminateExtensionCanceled:(BOOL)canceled;
|
||||
|
||||
@end
|
484
RiotShareExtension/Model/ShareExtensionManager.m
Normal file
484
RiotShareExtension/Model/ShareExtensionManager.m
Normal file
|
@ -0,0 +1,484 @@
|
|||
/*
|
||||
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 "ShareExtensionManager.h"
|
||||
#import "MXKPieChartHUD.h"
|
||||
@import MobileCoreServices;
|
||||
|
||||
typedef NS_ENUM(NSInteger, ImageCompressionMode)
|
||||
{
|
||||
ImageCompressionModeNone,
|
||||
ImageCompressionModeSmall,
|
||||
ImageCompressionModeMedium,
|
||||
ImageCompressionModeLarge
|
||||
};
|
||||
|
||||
@interface ShareExtensionManager ()
|
||||
|
||||
@property ImageCompressionMode imageCompressionMode;
|
||||
@property CGFloat actualLargeSize;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation ShareExtensionManager
|
||||
|
||||
#pragma mark - Lifecycle
|
||||
|
||||
+ (instancetype)sharedManager
|
||||
{
|
||||
static ShareExtensionManager *sharedInstance = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
sharedInstance = [[self alloc] init];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:sharedInstance selector:@selector(onMediaUploadProgress:) name:kMXMediaUploadProgressNotification object:nil];
|
||||
});
|
||||
return sharedInstance;
|
||||
}
|
||||
|
||||
#pragma mark - Public
|
||||
|
||||
- (void)sendContentToRoom:(MXRoom *)room failureBlock:(void(^)())failureBlock
|
||||
{
|
||||
NSString *UTTypeText = (__bridge NSString *)kUTTypeText;
|
||||
NSString *UTTypeURL = (__bridge NSString *)kUTTypeURL;
|
||||
NSString *UTTypeImage = (__bridge NSString *)kUTTypeImage;
|
||||
NSString *UTTypeVideo = (__bridge NSString *)kUTTypeVideo;
|
||||
NSString *UTTypeFileUrl = (__bridge NSString *)kUTTypeFileURL;
|
||||
NSString *UTTypeMovie = (__bridge NSString *)kUTTypeMovie;
|
||||
|
||||
__weak typeof(self) weakSelf = self;
|
||||
|
||||
for (NSExtensionItem *item in self.shareExtensionContext.inputItems)
|
||||
{
|
||||
for (NSItemProvider *itemProvider in item.attachments)
|
||||
{
|
||||
if ([itemProvider hasItemConformingToTypeIdentifier:UTTypeFileUrl])
|
||||
{
|
||||
[itemProvider loadItemForTypeIdentifier:UTTypeFileUrl options:nil completionHandler:^(NSURL *fileUrl, NSError * _Null_unspecified error) {
|
||||
if (weakSelf)
|
||||
{
|
||||
typeof(self) self = weakSelf;
|
||||
[self sendFileWithUrl:fileUrl toRoom:room extensionItem:item failureBlock:failureBlock];
|
||||
}
|
||||
}];
|
||||
}
|
||||
else if ([itemProvider hasItemConformingToTypeIdentifier:UTTypeText])
|
||||
{
|
||||
[itemProvider loadItemForTypeIdentifier:UTTypeText options:nil completionHandler:^(NSString *text, NSError * _Null_unspecified error) {
|
||||
if (weakSelf)
|
||||
{
|
||||
typeof(self) self = weakSelf;
|
||||
[self sendText:text toRoom:room extensionItem:item failureBlock:failureBlock];
|
||||
}
|
||||
}];
|
||||
}
|
||||
else if ([itemProvider hasItemConformingToTypeIdentifier:UTTypeURL])
|
||||
{
|
||||
[itemProvider loadItemForTypeIdentifier:UTTypeURL options:nil completionHandler:^(NSURL *url, NSError * _Null_unspecified error) {
|
||||
if (weakSelf)
|
||||
{
|
||||
typeof(self) self = weakSelf;
|
||||
[self sendText:url.absoluteString toRoom:room extensionItem:item failureBlock:failureBlock];
|
||||
}
|
||||
}];
|
||||
}
|
||||
else if ([itemProvider hasItemConformingToTypeIdentifier:UTTypeImage])
|
||||
{
|
||||
[itemProvider loadItemForTypeIdentifier:UTTypeImage options:nil completionHandler:^(NSData *imageData, NSError * _Null_unspecified error)
|
||||
{
|
||||
if (weakSelf)
|
||||
{
|
||||
typeof(self) self = weakSelf;
|
||||
UIImage *image = [[UIImage alloc] initWithData:imageData];
|
||||
UIAlertController *compressionPrompt = [self compressionPromptForImage:image shareBlock:^{
|
||||
[self sendImage:imageData withProvider:itemProvider toRoom:room extensionItem:item failureBlock:failureBlock];
|
||||
}];
|
||||
[self.delegate shareExtensionManager:self showImageCompressionPrompt:compressionPrompt];
|
||||
}
|
||||
}];
|
||||
}
|
||||
else if ([itemProvider hasItemConformingToTypeIdentifier:UTTypeVideo])
|
||||
{
|
||||
[itemProvider loadItemForTypeIdentifier:UTTypeVideo options:nil completionHandler:^(NSURL *videoLocalUrl, NSError * _Null_unspecified error)
|
||||
{
|
||||
if (weakSelf)
|
||||
{
|
||||
typeof(self) self = weakSelf;
|
||||
[self sendVideo:videoLocalUrl toRoom:room extensionItem:item failureBlock:failureBlock];
|
||||
}
|
||||
}];
|
||||
}
|
||||
else if ([itemProvider hasItemConformingToTypeIdentifier:UTTypeMovie])
|
||||
{
|
||||
[itemProvider loadItemForTypeIdentifier:UTTypeMovie options:nil completionHandler:^(NSURL *videoLocalUrl, NSError * _Null_unspecified error)
|
||||
{
|
||||
if (weakSelf)
|
||||
{
|
||||
typeof(self) self = weakSelf;
|
||||
[self sendVideo:videoLocalUrl toRoom:room extensionItem:item failureBlock:failureBlock];
|
||||
}
|
||||
}];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)hasImageTypeContent
|
||||
{
|
||||
for (NSExtensionItem *item in self.shareExtensionContext.inputItems)
|
||||
{
|
||||
for (NSItemProvider *itemProvider in item.attachments)
|
||||
{
|
||||
if ([itemProvider hasItemConformingToTypeIdentifier:(__bridge NSString *)kUTTypeImage])
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)terminateExtensionCanceled:(BOOL)canceled
|
||||
{
|
||||
if (canceled)
|
||||
{
|
||||
[self.shareExtensionContext cancelRequestWithError:[NSError errorWithDomain:@"MXUserCancelErrorDomain" code:4201 userInfo:nil]];
|
||||
}
|
||||
else
|
||||
{
|
||||
[self.shareExtensionContext cancelRequestWithError:[NSError errorWithDomain:@"MXFailureErrorDomain" code:500 userInfo:nil]];
|
||||
}
|
||||
}
|
||||
|
||||
- (UIAlertController *)compressionPromptForImage:(UIImage *)image shareBlock:(nonnull void(^)())shareBlock
|
||||
{
|
||||
UIAlertController *compressionPrompt;
|
||||
|
||||
// Get availabe sizes for this image
|
||||
MXKImageCompressionSizes compressionSizes = [MXKTools availableCompressionSizesForImage:image];
|
||||
|
||||
// Apply the compression mode
|
||||
if (compressionSizes.small.fileSize || compressionSizes.medium.fileSize || compressionSizes.large.fileSize)
|
||||
{
|
||||
__weak typeof(self) weakSelf = self;
|
||||
|
||||
compressionPrompt = [UIAlertController alertControllerWithTitle:[NSBundle mxk_localizedStringForKey:@"attachment_size_prompt"] message:nil preferredStyle:UIAlertControllerStyleActionSheet];
|
||||
|
||||
if (compressionSizes.small.fileSize)
|
||||
{
|
||||
NSString *resolution = [NSString stringWithFormat:@"%@ (%d x %d)", [MXTools fileSizeToString:compressionSizes.small.fileSize round:NO], (int)compressionSizes.small.imageSize.width, (int)compressionSizes.small.imageSize.height];
|
||||
|
||||
NSString *title = [NSString stringWithFormat:[NSBundle mxk_localizedStringForKey:@"attachment_small"], resolution];
|
||||
|
||||
[compressionPrompt addAction:[UIAlertAction actionWithTitle:title
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {
|
||||
|
||||
if (weakSelf)
|
||||
{
|
||||
typeof(self) self = weakSelf;
|
||||
|
||||
// Send the small image
|
||||
self.imageCompressionMode = ImageCompressionModeSmall;
|
||||
if (shareBlock)
|
||||
{
|
||||
shareBlock();
|
||||
}
|
||||
|
||||
[compressionPrompt dismissViewControllerAnimated:YES completion:nil];
|
||||
}
|
||||
|
||||
}]];
|
||||
}
|
||||
|
||||
if (compressionSizes.medium.fileSize)
|
||||
{
|
||||
NSString *resolution = [NSString stringWithFormat:@"%@ (%d x %d)", [MXTools fileSizeToString:compressionSizes.medium.fileSize round:NO], (int)compressionSizes.medium.imageSize.width, (int)compressionSizes.medium.imageSize.height];
|
||||
|
||||
NSString *title = [NSString stringWithFormat:[NSBundle mxk_localizedStringForKey:@"attachment_medium"], resolution];
|
||||
|
||||
[compressionPrompt addAction:[UIAlertAction actionWithTitle:title
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {
|
||||
|
||||
if (weakSelf)
|
||||
{
|
||||
typeof(self) self = weakSelf;
|
||||
|
||||
// Send the medium image
|
||||
self.imageCompressionMode = ImageCompressionModeMedium;
|
||||
if (shareBlock)
|
||||
{
|
||||
shareBlock();
|
||||
}
|
||||
|
||||
[compressionPrompt dismissViewControllerAnimated:YES completion:nil];
|
||||
}
|
||||
|
||||
}]];
|
||||
}
|
||||
|
||||
if (compressionSizes.large.fileSize)
|
||||
{
|
||||
NSString *resolution = [NSString stringWithFormat:@"%@ (%d x %d)", [MXTools fileSizeToString:compressionSizes.large.fileSize round:NO], (int)compressionSizes.large.imageSize.width, (int)compressionSizes.large.imageSize.height];
|
||||
|
||||
NSString *title = [NSString stringWithFormat:[NSBundle mxk_localizedStringForKey:@"attachment_large"], resolution];
|
||||
|
||||
[compressionPrompt addAction:[UIAlertAction actionWithTitle:title
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {
|
||||
|
||||
if (weakSelf)
|
||||
{
|
||||
typeof(self) self = weakSelf;
|
||||
|
||||
// Send the large image
|
||||
self.imageCompressionMode = ImageCompressionModeLarge;
|
||||
self.actualLargeSize = compressionSizes.actualLargeSize;
|
||||
if (shareBlock)
|
||||
{
|
||||
shareBlock();
|
||||
}
|
||||
|
||||
[compressionPrompt dismissViewControllerAnimated:YES completion:nil];
|
||||
}
|
||||
|
||||
}]];
|
||||
}
|
||||
|
||||
NSString *resolution = [NSString stringWithFormat:@"%@ (%d x %d)", [MXTools fileSizeToString:compressionSizes.original.fileSize round:NO], (int)compressionSizes.original.imageSize.width, (int)compressionSizes.original.imageSize.height];
|
||||
|
||||
NSString *title = [NSString stringWithFormat:[NSBundle mxk_localizedStringForKey:@"attachment_original"], resolution];
|
||||
|
||||
[compressionPrompt addAction:[UIAlertAction actionWithTitle:title
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {
|
||||
|
||||
if (weakSelf)
|
||||
{
|
||||
typeof(self) self = weakSelf;
|
||||
|
||||
self.imageCompressionMode = ImageCompressionModeNone;
|
||||
if (shareBlock)
|
||||
{
|
||||
shareBlock();
|
||||
}
|
||||
|
||||
[compressionPrompt dismissViewControllerAnimated:YES completion:nil];
|
||||
}
|
||||
|
||||
}]];
|
||||
|
||||
[compressionPrompt addAction:[UIAlertAction actionWithTitle:[NSBundle mxk_localizedStringForKey:@"cancel"]
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {
|
||||
|
||||
if (weakSelf)
|
||||
{
|
||||
[compressionPrompt dismissViewControllerAnimated:YES completion:nil];
|
||||
}
|
||||
|
||||
}]];
|
||||
|
||||
|
||||
}
|
||||
|
||||
return compressionPrompt;
|
||||
}
|
||||
|
||||
#pragma mark - Notifications
|
||||
|
||||
- (void)onMediaUploadProgress:(NSNotification *)notification
|
||||
{
|
||||
if ([self.delegate respondsToSelector:@selector(shareExtensionManager:mediaUploadProgress:)])
|
||||
{
|
||||
[self.delegate shareExtensionManager:self mediaUploadProgress:((NSNumber *)notification.userInfo[kMXMediaLoaderProgressValueKey]).floatValue];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Sharing
|
||||
|
||||
- (void)sendText:(NSString *)text toRoom:(MXRoom *)room extensionItem:(NSExtensionItem *)extensionItem failureBlock:(void(^)())failureBlock
|
||||
{
|
||||
if (!text)
|
||||
{
|
||||
NSLog(@"[ShareExtensionManager] loadItemForTypeIdentifier: failed.");
|
||||
if (failureBlock)
|
||||
{
|
||||
failureBlock();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
__weak typeof(self) weakSelf = self;
|
||||
|
||||
[room sendTextMessage:text success:^(NSString *eventId) {
|
||||
if (weakSelf)
|
||||
{
|
||||
typeof(self) self = weakSelf;
|
||||
[self.shareExtensionContext completeRequestReturningItems:@[extensionItem] completionHandler:nil];
|
||||
}
|
||||
} failure:^(NSError *error) {
|
||||
NSLog(@"[ShareExtensionManager] sendTextMessage failed.");
|
||||
if (failureBlock)
|
||||
{
|
||||
failureBlock();
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)sendFileWithUrl:(NSURL *)fileUrl toRoom:(MXRoom *)room extensionItem:(NSExtensionItem *)extensionItem failureBlock:(void(^)())failureBlock
|
||||
{
|
||||
if (!fileUrl)
|
||||
{
|
||||
NSLog(@"[ShareExtensionManager] loadItemForTypeIdentifier: failed.");
|
||||
if (failureBlock)
|
||||
{
|
||||
failureBlock();
|
||||
}
|
||||
return;
|
||||
}
|
||||
NSString *mimeType = [fileUrl pathExtension];
|
||||
|
||||
__weak typeof(self) weakSelf = self;
|
||||
|
||||
[room sendFile:fileUrl mimeType:mimeType localEcho:nil success:^(NSString *eventId) {
|
||||
if (weakSelf)
|
||||
{
|
||||
typeof(self) self = weakSelf;
|
||||
[self.shareExtensionContext completeRequestReturningItems:@[extensionItem] completionHandler:nil];
|
||||
}
|
||||
} failure:^(NSError *error) {
|
||||
NSLog(@"[ShareExtensionManager] sendFile failed.");
|
||||
if (failureBlock)
|
||||
{
|
||||
failureBlock();
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)sendImage:(NSData *)imageData withProvider:(NSItemProvider*)itemProvider toRoom:(MXRoom *)room extensionItem:(NSExtensionItem *)extensionItem failureBlock:(void(^)())failureBlock
|
||||
{
|
||||
if (!imageData)
|
||||
{
|
||||
NSLog(@"[ShareExtensionManager] loadItemForTypeIdentifier: failed.");
|
||||
if (failureBlock)
|
||||
{
|
||||
failureBlock();
|
||||
}
|
||||
return;
|
||||
}
|
||||
//Send the image
|
||||
UIImage *image = [[UIImage alloc] initWithData: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)];
|
||||
}
|
||||
|
||||
NSString *mimeType;
|
||||
if ([itemProvider hasItemConformingToTypeIdentifier:(__bridge NSString *)kUTTypePNG])
|
||||
{
|
||||
mimeType = @"image/png";
|
||||
}
|
||||
else if ([itemProvider hasItemConformingToTypeIdentifier:(__bridge NSString *)kUTTypeJPEG])
|
||||
{
|
||||
mimeType = @"image/jpeg";
|
||||
}
|
||||
else
|
||||
{
|
||||
image = [[UIImage alloc] initWithData:UIImageJPEGRepresentation(image, 1.0)];
|
||||
mimeType = @"image/jpeg";
|
||||
}
|
||||
|
||||
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:imageData withImageSize:image.size mimeType:mimeType andThumbnail:thumbnail localEcho:nil success:^(NSString *eventId) {
|
||||
if (weakSelf)
|
||||
{
|
||||
typeof(self) self = weakSelf;
|
||||
[self.shareExtensionContext 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
|
||||
{
|
||||
if (!videoLocalUrl)
|
||||
{
|
||||
NSLog(@"[ShareExtensionManager] loadItemForTypeIdentifier: failed.");
|
||||
if (failureBlock)
|
||||
{
|
||||
failureBlock();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Retrieve the video frame at 1 sec to define the video thumbnail
|
||||
AVURLAsset *urlAsset = [[AVURLAsset alloc] initWithURL:videoLocalUrl options:nil];
|
||||
AVAssetImageGenerator *assetImageGenerator = [AVAssetImageGenerator assetImageGeneratorWithAsset:urlAsset];
|
||||
assetImageGenerator.appliesPreferredTrackTransform = YES;
|
||||
CMTime time = CMTimeMake(1, 1);
|
||||
CGImageRef imageRef = [assetImageGenerator copyCGImageAtTime:time actualTime:NULL error:nil];
|
||||
// Finalize video attachment
|
||||
UIImage *videoThumbnail = [[UIImage alloc] initWithCGImage:imageRef];
|
||||
CFRelease(imageRef);
|
||||
|
||||
__weak typeof(self) weakSelf = self;
|
||||
|
||||
[room sendVideo:videoLocalUrl withThumbnail:videoThumbnail localEcho:nil success:^(NSString *eventId) {
|
||||
if (weakSelf)
|
||||
{
|
||||
typeof(self) self = weakSelf;
|
||||
[self.shareExtensionContext completeRequestReturningItems:@[extensionItem] completionHandler:nil];
|
||||
}
|
||||
} failure:^(NSError *error) {
|
||||
NSLog(@"[ShareExtensionManager] sendVideo failed.");
|
||||
if (failureBlock)
|
||||
{
|
||||
failureBlock();
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
|
||||
@end
|
29
RiotShareExtension/Model/ShareRecentsDataSource.h
Normal file
29
RiotShareExtension/Model/ShareRecentsDataSource.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
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, ShareRecentsDataSourceMode)
|
||||
{
|
||||
RecentsDataSourceModePeople,
|
||||
RecentsDataSourceModeRooms
|
||||
};
|
||||
|
||||
@interface ShareRecentsDataSource : MXKRecentsDataSource
|
||||
|
||||
- (instancetype)initWithMatrixSession:(MXSession *)mxSession dataSourceMode:(ShareRecentsDataSourceMode)dataSourceMode;
|
||||
|
||||
@end
|
144
RiotShareExtension/Model/ShareRecentsDataSource.m
Normal file
144
RiotShareExtension/Model/ShareRecentsDataSource.m
Normal file
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
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)
|
||||
{
|
||||
[self.recentPeople addObject:cellData];
|
||||
}
|
||||
}
|
||||
else if (self.dataSourceMode == RecentsDataSourceModeRooms)
|
||||
{
|
||||
if (!room.isDirect)
|
||||
{
|
||||
[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
|
21
RiotShareExtension/ViewController/FallbackViewController.h
Normal file
21
RiotShareExtension/ViewController/FallbackViewController.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
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>
|
||||
|
||||
@interface FallbackViewController : MXKViewController
|
||||
|
||||
@end
|
42
RiotShareExtension/ViewController/FallbackViewController.m
Normal file
42
RiotShareExtension/ViewController/FallbackViewController.m
Normal file
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
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 "FallbackViewController.h"
|
||||
#import "RiotDesignValues.h"
|
||||
|
||||
@interface FallbackViewController ()
|
||||
|
||||
@property (weak, nonatomic) IBOutlet UILabel *titleLabel;
|
||||
|
||||
@end
|
||||
|
||||
@implementation FallbackViewController
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
|
||||
self.titleLabel.textColor = kRiotSecondaryTextColor;
|
||||
self.titleLabel.text = NSLocalizedStringFromTable(@"auth_share_extension_prompt", @"Vector", nil);
|
||||
}
|
||||
|
||||
- (void)didReceiveMemoryWarning
|
||||
{
|
||||
[super didReceiveMemoryWarning];
|
||||
// Dispose of any resources that can be recreated.
|
||||
}
|
||||
|
||||
@end
|
63
RiotShareExtension/ViewController/FallbackViewController.xib
Normal file
63
RiotShareExtension/ViewController/FallbackViewController.xib
Normal file
|
@ -0,0 +1,63 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="12120" systemVersion="16F73" 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="12088"/>
|
||||
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="FallbackViewController">
|
||||
<connections>
|
||||
<outlet property="titleLabel" destination="9jC-d4-VqL" id="J3Y-oL-e29"/>
|
||||
<outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
|
||||
</connections>
|
||||
</placeholder>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="4cM-h2-CkH">
|
||||
<rect key="frame" x="56.5" y="133.5" width="262.5" height="400"/>
|
||||
<subviews>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="animatedLogo-4.png" translatesAutoresizingMaskIntoConstraints="NO" id="bAn-eK-zqg">
|
||||
<rect key="frame" x="20" y="0.0" width="222.5" height="372.5"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
</imageView>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="252" verticalCompressionResistancePriority="752" text="loc:prompt" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="9jC-d4-VqL">
|
||||
<rect key="frame" x="0.0" y="372.5" width="262.5" height="27.5"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="23"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="bAn-eK-zqg" secondAttribute="trailing" constant="20" id="5V5-75-4Cp"/>
|
||||
<constraint firstItem="bAn-eK-zqg" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="4cM-h2-CkH" secondAttribute="leading" constant="20" id="C2v-9e-YjU"/>
|
||||
<constraint firstAttribute="trailing" secondItem="9jC-d4-VqL" secondAttribute="trailing" id="DrH-g4-EBL"/>
|
||||
<constraint firstItem="bAn-eK-zqg" firstAttribute="top" secondItem="4cM-h2-CkH" secondAttribute="top" id="HKr-Vy-i8P"/>
|
||||
<constraint firstAttribute="bottom" secondItem="9jC-d4-VqL" secondAttribute="bottom" id="LNV-E1-kCG"/>
|
||||
<constraint firstItem="9jC-d4-VqL" firstAttribute="leading" secondItem="4cM-h2-CkH" secondAttribute="leading" id="RGz-7h-0dt"/>
|
||||
<constraint firstItem="9jC-d4-VqL" firstAttribute="top" secondItem="bAn-eK-zqg" secondAttribute="bottom" id="bgG-1y-R8q"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstItem="4cM-h2-CkH" firstAttribute="width" secondItem="i5M-Pr-FkT" secondAttribute="width" multiplier="0.7" id="8Lf-tE-JWS"/>
|
||||
<constraint firstItem="4cM-h2-CkH" firstAttribute="centerX" secondItem="i5M-Pr-FkT" secondAttribute="centerX" id="QsS-hg-ULo"/>
|
||||
<constraint firstItem="4cM-h2-CkH" firstAttribute="centerY" secondItem="i5M-Pr-FkT" secondAttribute="centerY" id="taY-I3-zBr"/>
|
||||
<constraint firstItem="4cM-h2-CkH" firstAttribute="height" secondItem="i5M-Pr-FkT" secondAttribute="height" multiplier="0.6" id="uaL-do-Rlq"/>
|
||||
</constraints>
|
||||
<point key="canvasLocation" x="33.5" y="64.5"/>
|
||||
</view>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="animatedLogo-4.png" width="300" height="300"/>
|
||||
</resources>
|
||||
</document>
|
25
RiotShareExtension/ViewController/RoomsListViewController.h
Normal file
25
RiotShareExtension/ViewController/RoomsListViewController.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
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 <UIKit/UIKit.h>
|
||||
#import "MXRoom+Riot.h"
|
||||
#import "ShareRecentsDataSource.h"
|
||||
|
||||
@interface RoomsListViewController : UIViewController <MXKDataSourceDelegate>
|
||||
|
||||
+ (instancetype)listViewControllerWithDataSource:(ShareRecentsDataSource *)dataSource failureBlock:(void(^)())failureBlock;
|
||||
|
||||
@end
|
219
RiotShareExtension/ViewController/RoomsListViewController.m
Normal file
219
RiotShareExtension/ViewController/RoomsListViewController.m
Normal file
|
@ -0,0 +1,219 @@
|
|||
/*
|
||||
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 "RoomsListViewController.h"
|
||||
#import "RoomTableViewCell.h"
|
||||
#import "NSBundle+MatrixKit.h"
|
||||
#import "ShareExtensionManager.h"
|
||||
#import "RecentCellData.h"
|
||||
#import "RiotDesignValues.h"
|
||||
#import "MXKPieChartView.h"
|
||||
#import "MXKPieChartHUD.h"
|
||||
|
||||
|
||||
|
||||
@interface RoomsListViewController () <UITableViewDelegate, UISearchBarDelegate, ShareExtensionManagerDelegate>
|
||||
|
||||
@property (nonatomic) ShareRecentsDataSource *dataSource;
|
||||
@property (copy) void (^failureBlock)();
|
||||
|
||||
@property (nonatomic) UITableView *mainTableView;
|
||||
@property (nonatomic) UISearchBar *searchBar;
|
||||
@property (nonatomic) MXKPieChartHUD *hudView;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation RoomsListViewController
|
||||
|
||||
#pragma mark - Lifecycle
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
[self configureTableView];
|
||||
[self configureSearchBar];
|
||||
}
|
||||
|
||||
#pragma mark - Public
|
||||
|
||||
+ (instancetype)listViewControllerWithDataSource:(ShareRecentsDataSource *)dataSource failureBlock:(void(^)())failureBlock
|
||||
{
|
||||
RoomsListViewController *listViewController = [[self class] new];
|
||||
listViewController.dataSource = dataSource;
|
||||
listViewController.failureBlock = failureBlock;
|
||||
return listViewController;
|
||||
}
|
||||
|
||||
#pragma mark - Views
|
||||
|
||||
- (void)configureTableView
|
||||
{
|
||||
self.mainTableView = [[UITableView alloc] initWithFrame:self.view.frame style:UITableViewStylePlain];
|
||||
self.mainTableView.dataSource = self.dataSource;
|
||||
self.mainTableView.delegate = self;
|
||||
[self.mainTableView registerNib:[RoomTableViewCell nib] forCellReuseIdentifier:[RoomTableViewCell defaultReuseIdentifier]];
|
||||
|
||||
[self.view addSubview:self.mainTableView];
|
||||
self.mainTableView.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
self.view.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintWithItem:self.mainTableView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeWidth multiplier:1 constant:0];
|
||||
NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintWithItem:self.mainTableView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeHeight multiplier:1 constant:0];
|
||||
NSLayoutConstraint *centerXConstraint = [NSLayoutConstraint constraintWithItem:self.mainTableView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1 constant:0];
|
||||
NSLayoutConstraint *centerYConstraint = [NSLayoutConstraint constraintWithItem:self.mainTableView attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterY multiplier:1 constant:0];
|
||||
|
||||
[NSLayoutConstraint activateConstraints:@[widthConstraint, heightConstraint, centerXConstraint, centerYConstraint]];
|
||||
}
|
||||
|
||||
- (void)configureSearchBar
|
||||
{
|
||||
self.searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0.0, 0.0, self.view.frame.size.width, 44.0)];
|
||||
self.searchBar.searchBarStyle = UISearchBarStyleMinimal;
|
||||
self.searchBar.placeholder = NSLocalizedStringFromTable(@"search_default_placeholder", @"Vector", nil);
|
||||
self.searchBar.tintColor = kRiotColorGreen;
|
||||
self.searchBar.showsCancelButton = YES;
|
||||
|
||||
self.searchBar.delegate = self;
|
||||
|
||||
self.mainTableView.tableHeaderView = self.searchBar;
|
||||
}
|
||||
|
||||
#pragma mark - Private
|
||||
|
||||
- (void)showShareAlertForRoomPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
NSString *receipantName = [self.dataSource getRoomAtIndexPath:indexPath].riotDisplayname;
|
||||
if (!receipantName.length)
|
||||
{
|
||||
receipantName = NSLocalizedStringFromTable(@"room_displayname_no_title", @"Vector", nil);
|
||||
}
|
||||
|
||||
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:[NSString stringWithFormat:NSLocalizedStringFromTable(@"send_to", @"Vector", nil), receipantName] 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];
|
||||
|
||||
self.hudView = [MXKPieChartHUD showLoadingHudOnView:self.view WithMessage:NSLocalizedStringFromTable(@"sending", @"Vector", nil)];
|
||||
[ShareExtensionManager sharedManager].delegate = self;
|
||||
self.parentViewController.view.userInteractionEnabled = NO;
|
||||
|
||||
[[ShareExtensionManager sharedManager] sendContentToRoom:selectedRoom failureBlock:^{
|
||||
[self showFailureAlert];
|
||||
}];
|
||||
}];
|
||||
[alertController addAction:sendAction];
|
||||
|
||||
[self presentViewController:alertController animated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (void)showFailureAlert
|
||||
{
|
||||
UIAlertController *alertController = [UIAlertController alertControllerWithTitle: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)
|
||||
{
|
||||
self.failureBlock();
|
||||
}
|
||||
}];
|
||||
[alertController addAction:okAction];
|
||||
[self presentViewController:alertController animated:YES completion:nil];
|
||||
}
|
||||
|
||||
#pragma mark - UITableViewDelegate
|
||||
|
||||
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
return [RoomTableViewCell cellHeight];
|
||||
}
|
||||
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
[tableView deselectRowAtIndexPath:indexPath animated:YES];
|
||||
|
||||
[self showShareAlertForRoomPath:indexPath];
|
||||
}
|
||||
|
||||
#pragma mark - MXKDataSourceDelegate
|
||||
|
||||
- (void)dataSource:(MXKDataSource*)dataSource didCellChange:(id)changes
|
||||
{
|
||||
if (dataSource == self.dataSource)
|
||||
{
|
||||
[self.mainTableView reloadData];
|
||||
}
|
||||
}
|
||||
|
||||
- (Class<MXKCellRendering>)cellViewClassForCellData:(MXKCellData*)cellData
|
||||
{
|
||||
if ([cellData isKindOfClass:[RecentCellData class]])
|
||||
{
|
||||
return [RoomTableViewCell class];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSString *)cellReuseIdentifierForCellData:(MXKCellData*)cellData
|
||||
{
|
||||
if ([cellData isKindOfClass:[MXKRecentCellData class]])
|
||||
{
|
||||
return [RoomTableViewCell defaultReuseIdentifier];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
#pragma mark - UISearchBarDelegate
|
||||
|
||||
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
|
||||
{
|
||||
if (searchText.length)
|
||||
{
|
||||
[self.dataSource searchWithPatterns:@[searchText]];
|
||||
}
|
||||
else
|
||||
{
|
||||
[self.dataSource searchWithPatterns:nil];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
|
||||
{
|
||||
[searchBar resignFirstResponder];
|
||||
}
|
||||
|
||||
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar
|
||||
{
|
||||
[searchBar resignFirstResponder];
|
||||
[self.dataSource searchWithPatterns:nil];
|
||||
}
|
||||
|
||||
#pragma mark - ShareExtensionManagerDelegate
|
||||
|
||||
- (void)shareExtensionManager:(ShareExtensionManager *)extensionManager showImageCompressionPrompt:(UIAlertController *)compressionPrompt
|
||||
{
|
||||
[compressionPrompt popoverPresentationController].sourceView = self.view;
|
||||
[compressionPrompt popoverPresentationController].sourceRect = self.view.frame;
|
||||
[self presentViewController:compressionPrompt animated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (void)shareExtensionManager:(ShareExtensionManager *)extensionManager mediaUploadProgress:(CGFloat)progress
|
||||
{
|
||||
[self.hudView setProgress:progress];
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
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 <UIKit/UIKit.h>
|
||||
|
||||
@interface SharePresentingViewController : UIViewController
|
||||
|
||||
@end
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
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 "SharePresentingViewController.h"
|
||||
#import "ShareViewController.h"
|
||||
#import "ShareExtensionManager.h"
|
||||
|
||||
@interface SharePresentingViewController ()
|
||||
|
||||
@end
|
||||
|
||||
@implementation SharePresentingViewController
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
|
||||
[ShareExtensionManager sharedManager].shareExtensionContext = self.extensionContext;
|
||||
|
||||
[self presentShareViewController];
|
||||
}
|
||||
|
||||
- (void)presentShareViewController
|
||||
{
|
||||
ShareViewController *shareViewController = [[ShareViewController alloc] init];
|
||||
|
||||
shareViewController.providesPresentationContextTransitionStyle = YES;
|
||||
shareViewController.definesPresentationContext = YES;
|
||||
shareViewController.modalPresentationStyle = UIModalPresentationOverFullScreen;
|
||||
shareViewController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
|
||||
|
||||
[self presentViewController:shareViewController animated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (void)didReceiveMemoryWarning
|
||||
{
|
||||
[super didReceiveMemoryWarning];
|
||||
// Dispose of any resources that can be recreated.
|
||||
}
|
||||
|
||||
|
||||
@end
|
23
RiotShareExtension/ViewController/ShareViewController.h
Normal file
23
RiotShareExtension/ViewController/ShareViewController.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
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 <UIKit/UIKit.h>
|
||||
#import <Social/Social.h>
|
||||
#import <MatrixKit/MatrixKit.h>
|
||||
|
||||
@interface ShareViewController : MXKViewController
|
||||
|
||||
@end
|
178
RiotShareExtension/ViewController/ShareViewController.m
Normal file
178
RiotShareExtension/ViewController/ShareViewController.m
Normal file
|
@ -0,0 +1,178 @@
|
|||
/*
|
||||
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 "ShareViewController.h"
|
||||
#import "SegmentedViewController.h"
|
||||
#import "RoomsListViewController.h"
|
||||
#import "FallbackViewController.h"
|
||||
#import "ShareRecentsDataSource.h"
|
||||
#import "ShareExtensionManager.h"
|
||||
|
||||
|
||||
@interface ShareViewController ()
|
||||
|
||||
@property (nonatomic) NSArray <MXRoom *> *rooms;
|
||||
|
||||
@property (nonatomic) MXKRecentsDataSource *recentsDataSource;
|
||||
|
||||
@property (weak, nonatomic) IBOutlet UIView *masterContainerView;
|
||||
@property (weak, nonatomic) IBOutlet UILabel *tittleLabel;
|
||||
@property (weak, nonatomic) IBOutlet UIView *contentView;
|
||||
|
||||
@property (nonatomic) SegmentedViewController *segmentedViewController;
|
||||
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation ShareViewController
|
||||
|
||||
#pragma mark - Lifecycle
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
|
||||
[self prepareSession];
|
||||
[self configureViews];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onSessionSync:) name:kMXSessionDidSyncNotification object:nil];
|
||||
}
|
||||
|
||||
- (void)viewWillDisappear:(BOOL)animated
|
||||
{
|
||||
[super viewWillDisappear:animated];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
}
|
||||
|
||||
#pragma mark - Private
|
||||
|
||||
- (void)prepareSession
|
||||
{
|
||||
// Apply the application group
|
||||
[MXKAppSettings standardAppSettings].applicationGroup = @"group.im.vector";
|
||||
|
||||
// Prepare account manager
|
||||
MXKAccountManager *accountManager = [MXKAccountManager sharedManager];
|
||||
|
||||
// Use MXFileStore as MXStore to permanently store events.
|
||||
accountManager.storeClass = [MXFileStore class];
|
||||
|
||||
// Start a matrix session for each enabled accounts.
|
||||
NSLog(@"[AppDelegate] initMatrixSessions: prepareSessionForActiveAccounts");
|
||||
[accountManager prepareSessionForActiveAccounts];
|
||||
|
||||
// Resume all existing matrix sessions
|
||||
NSArray *mxAccounts = accountManager.activeAccounts;
|
||||
for (MXKAccount *account in mxAccounts)
|
||||
{
|
||||
[account resume];
|
||||
[self addMatrixSession:account.mxSession];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)configureViews
|
||||
{
|
||||
self.masterContainerView.layer.cornerRadius = 7;
|
||||
|
||||
if (self.mainSession)
|
||||
{
|
||||
self.tittleLabel.text = [NSString stringWithFormat:NSLocalizedStringFromTable(@"send_to", @"Vector", nil), @""];
|
||||
[self configureSegmentedViewController];
|
||||
}
|
||||
else
|
||||
{
|
||||
NSDictionary *infoDictionary = [NSBundle mainBundle].infoDictionary;
|
||||
NSString *bundleDisplayName = [infoDictionary objectForKey:@"CFBundleDisplayName"];
|
||||
self.tittleLabel.text = bundleDisplayName;
|
||||
[self configureFallbackViewController];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)configureSegmentedViewController
|
||||
{
|
||||
self.segmentedViewController = [SegmentedViewController segmentedViewController];
|
||||
|
||||
NSArray *titles = @[NSLocalizedStringFromTable(@"title_rooms", @"Vector", nil) , NSLocalizedStringFromTable(@"title_people", @"Vector", nil)];
|
||||
|
||||
void (^failureBlock)() = ^void() {
|
||||
[self dismissViewControllerAnimated:YES completion:^{
|
||||
[[ShareExtensionManager sharedManager] terminateExtensionCanceled:NO];
|
||||
}];
|
||||
};
|
||||
|
||||
ShareRecentsDataSource *roomsDataSource = [[ShareRecentsDataSource alloc] initWithMatrixSession:self.mainSession dataSourceMode:RecentsDataSourceModeRooms];
|
||||
RoomsListViewController *roomsViewController = [RoomsListViewController listViewControllerWithDataSource:roomsDataSource failureBlock:failureBlock];
|
||||
roomsDataSource.delegate = roomsViewController;
|
||||
|
||||
ShareRecentsDataSource *peopleDataSource = [[ShareRecentsDataSource alloc] initWithMatrixSession:self.mainSession dataSourceMode:RecentsDataSourceModePeople];
|
||||
RoomsListViewController *peopleViewController = [RoomsListViewController listViewControllerWithDataSource:peopleDataSource failureBlock:failureBlock];
|
||||
peopleDataSource.delegate = peopleViewController;
|
||||
|
||||
[self.segmentedViewController initWithTitles:titles viewControllers:@[roomsViewController, peopleViewController] defaultSelected:0];
|
||||
|
||||
[self addChildViewController:self.segmentedViewController];
|
||||
[self.contentView addSubview:self.segmentedViewController.view];
|
||||
[self.segmentedViewController didMoveToParentViewController:self];
|
||||
|
||||
[self autoPinSubviewEdges:self.segmentedViewController.view toSuperviewEdges:self.contentView];
|
||||
}
|
||||
|
||||
- (void)configureFallbackViewController
|
||||
{
|
||||
FallbackViewController *fallbackVC = [FallbackViewController new];
|
||||
[self addChildViewController:fallbackVC];
|
||||
[self.contentView addSubview:fallbackVC.view];
|
||||
[fallbackVC didMoveToParentViewController:self];
|
||||
|
||||
[self autoPinSubviewEdges:fallbackVC.view toSuperviewEdges:self.contentView];
|
||||
}
|
||||
|
||||
- (void)autoPinSubviewEdges:(UIView *)subview toSuperviewEdges:(UIView *)superview
|
||||
{
|
||||
subview.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:superview attribute:NSLayoutAttributeWidth multiplier:1 constant:0];
|
||||
widthConstraint.active = YES;
|
||||
NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:superview attribute:NSLayoutAttributeHeight multiplier:1 constant:0];
|
||||
heightConstraint.active = YES;
|
||||
NSLayoutConstraint *centerXConstraint = [NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:superview attribute:NSLayoutAttributeCenterX multiplier:1 constant:0];
|
||||
centerXConstraint.active = YES;
|
||||
NSLayoutConstraint *centerYConstraint = [NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:superview attribute:NSLayoutAttributeCenterY multiplier:1 constant:0];
|
||||
centerYConstraint.active = YES;
|
||||
}
|
||||
|
||||
#pragma mark - Notifications
|
||||
|
||||
- (void)onSessionSync:(NSNotification *)notification
|
||||
{
|
||||
if ([notification.object isEqual:self.mainSession] && !self.rooms.count)
|
||||
{
|
||||
self.recentsDataSource = [[MXKRecentsDataSource alloc] initWithMatrixSession:self.mainSession];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Actions
|
||||
|
||||
- (IBAction)close:(UIButton *)sender
|
||||
{
|
||||
[self dismissViewControllerAnimated:YES completion:^{
|
||||
[[ShareExtensionManager sharedManager] terminateExtensionCanceled:YES];
|
||||
}];
|
||||
}
|
||||
|
||||
|
||||
@end
|
103
RiotShareExtension/ViewController/ShareViewController.xib
Normal file
103
RiotShareExtension/ViewController/ShareViewController.xib
Normal file
|
@ -0,0 +1,103 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="12120" systemVersion="16F73" 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="12088"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="ShareViewController">
|
||||
<connections>
|
||||
<outlet property="contentView" destination="jAn-9F-DlU" id="NWV-TS-MGK"/>
|
||||
<outlet property="masterContainerView" destination="oax-z3-vv0" id="KvN-B4-ZkF"/>
|
||||
<outlet property="tittleLabel" destination="BQ5-AW-rsV" id="qm6-T7-3LB"/>
|
||||
<outlet property="view" destination="Bej-An-0PZ" id="sgO-5Q-y1c"/>
|
||||
</connections>
|
||||
</placeholder>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<view opaque="NO" contentMode="scaleToFill" id="Bej-An-0PZ">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<view alpha="0.59999999999999998" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="0SU-xL-B4a" userLabel="Overlay View">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<color key="backgroundColor" red="0.16337278091968011" green="0.16337278091968011" blue="0.16337278091968011" alpha="1" colorSpace="custom" customColorSpace="displayP3"/>
|
||||
</view>
|
||||
<view clipsSubviews="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="oax-z3-vv0" userLabel="Master Container View">
|
||||
<rect key="frame" x="30" y="58.5" width="315" height="550"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="7Ye-Ni-Nsr" userLabel="Title Container View">
|
||||
<rect key="frame" x="0.0" y="0.0" width="315" height="40"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="BQ5-AW-rsV" userLabel="Title Label">
|
||||
<rect key="frame" x="132.5" y="8" width="51.5" height="24"/>
|
||||
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="20"/>
|
||||
<color key="textColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="RBD-vS-rcr">
|
||||
<rect key="frame" x="5" y="9" width="30" height="22"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="30" id="Pym-oR-KoO"/>
|
||||
</constraints>
|
||||
<state key="normal" image="cancel.png"/>
|
||||
<connections>
|
||||
<action selector="close:" destination="-1" eventType="touchUpInside" id="rko-d0-x9l"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstItem="BQ5-AW-rsV" firstAttribute="centerY" secondItem="7Ye-Ni-Nsr" secondAttribute="centerY" id="1d9-JD-CVF"/>
|
||||
<constraint firstItem="RBD-vS-rcr" firstAttribute="leading" secondItem="7Ye-Ni-Nsr" secondAttribute="leading" constant="5" id="Swk-mu-OcC"/>
|
||||
<constraint firstItem="BQ5-AW-rsV" firstAttribute="centerX" secondItem="7Ye-Ni-Nsr" secondAttribute="centerX" id="ZDz-XD-buD"/>
|
||||
<constraint firstAttribute="height" constant="40" id="dFb-An-mc6"/>
|
||||
<constraint firstItem="RBD-vS-rcr" firstAttribute="centerY" secondItem="7Ye-Ni-Nsr" secondAttribute="centerY" id="wUd-cN-mek"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="jAn-9F-DlU">
|
||||
<rect key="frame" x="0.0" y="40" width="315" height="510"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</view>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="trailing" secondItem="jAn-9F-DlU" secondAttribute="trailing" id="1ce-br-3uU"/>
|
||||
<constraint firstItem="jAn-9F-DlU" firstAttribute="top" secondItem="7Ye-Ni-Nsr" secondAttribute="bottom" id="1zc-qn-eFO"/>
|
||||
<constraint firstItem="7Ye-Ni-Nsr" firstAttribute="leading" secondItem="oax-z3-vv0" secondAttribute="leading" id="RTO-at-ZR0"/>
|
||||
<constraint firstAttribute="trailing" secondItem="7Ye-Ni-Nsr" secondAttribute="trailing" id="RtW-o3-kOS"/>
|
||||
<constraint firstAttribute="height" relation="lessThanOrEqual" constant="550" id="Uon-Cb-HY2"/>
|
||||
<constraint firstItem="7Ye-Ni-Nsr" firstAttribute="top" secondItem="oax-z3-vv0" secondAttribute="top" id="YIj-72-BeJ"/>
|
||||
<constraint firstAttribute="width" relation="lessThanOrEqual" constant="550" id="de2-m2-xUY"/>
|
||||
<constraint firstItem="jAn-9F-DlU" firstAttribute="leading" secondItem="oax-z3-vv0" secondAttribute="leading" id="hju-02-xMk"/>
|
||||
<constraint firstAttribute="bottom" secondItem="jAn-9F-DlU" secondAttribute="bottom" id="rDT-Zr-eUB"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="bottom" secondItem="0SU-xL-B4a" secondAttribute="bottom" id="51f-Wf-Yg2"/>
|
||||
<constraint firstAttribute="bottom" secondItem="oax-z3-vv0" secondAttribute="bottom" priority="750" constant="10" id="Qjd-aK-VSL"/>
|
||||
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="oax-z3-vv0" secondAttribute="trailing" constant="30" id="VUX-RZ-Jke"/>
|
||||
<constraint firstItem="0SU-xL-B4a" firstAttribute="top" secondItem="Bej-An-0PZ" secondAttribute="top" id="avs-GA-7eh"/>
|
||||
<constraint firstAttribute="trailing" secondItem="0SU-xL-B4a" secondAttribute="trailing" id="bgh-PD-Xqx"/>
|
||||
<constraint firstAttribute="trailing" secondItem="oax-z3-vv0" secondAttribute="trailing" priority="750" constant="30" id="cYZ-zQ-1Dh"/>
|
||||
<constraint firstItem="oax-z3-vv0" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="Bej-An-0PZ" secondAttribute="leading" constant="30" id="h8V-gU-iRt"/>
|
||||
<constraint firstItem="oax-z3-vv0" firstAttribute="centerY" secondItem="Bej-An-0PZ" secondAttribute="centerY" id="lbe-HZ-ZsR"/>
|
||||
<constraint firstItem="oax-z3-vv0" firstAttribute="top" secondItem="Bej-An-0PZ" secondAttribute="top" priority="750" constant="40" id="loD-b9-Eog"/>
|
||||
<constraint firstItem="oax-z3-vv0" firstAttribute="centerX" secondItem="Bej-An-0PZ" secondAttribute="centerX" id="mzY-Ok-RAp"/>
|
||||
<constraint firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="oax-z3-vv0" secondAttribute="bottom" constant="10" id="qnO-IP-fp3"/>
|
||||
<constraint firstItem="oax-z3-vv0" firstAttribute="leading" secondItem="Bej-An-0PZ" secondAttribute="leading" priority="750" constant="30" id="sYU-AK-85d"/>
|
||||
<constraint firstItem="oax-z3-vv0" firstAttribute="top" relation="greaterThanOrEqual" secondItem="Bej-An-0PZ" secondAttribute="top" constant="40" id="vXO-uW-nFN"/>
|
||||
<constraint firstItem="0SU-xL-B4a" firstAttribute="leading" secondItem="Bej-An-0PZ" secondAttribute="leading" id="wol-Zy-dCb"/>
|
||||
</constraints>
|
||||
<point key="canvasLocation" x="39.5" y="89.5"/>
|
||||
</view>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="cancel.png" width="20" height="20"/>
|
||||
</resources>
|
||||
</document>
|
Loading…
Reference in a new issue