From 6156cb0f78e1b0038d5279f5cc21cd4e55055543 Mon Sep 17 00:00:00 2001 From: giomfo Date: Mon, 24 Nov 2014 10:38:23 +0100 Subject: [PATCH] Rename directories of sample sources (matrixConsole) --- .gitignore | 29 + Podfile | 16 + Podfile.lock | 42 + README.rst | 11 + matrixConsole.xcodeproj/project.pbxproj | 640 ++++++ matrixConsole/AppDelegate.h | 36 + matrixConsole/AppDelegate.m | 133 ++ matrixConsole/AppSettings.h | 29 + matrixConsole/AppSettings.m | 89 + matrixConsole/Assets/close.png | Bin 0 -> 397 bytes matrixConsole/Assets/default-profile.png | Bin 0 -> 1722 bytes matrixConsole/Assets/gradient.png | Bin 0 -> 194 bytes matrixConsole/Assets/logo.png | Bin 0 -> 910 bytes matrixConsole/Assets/logoHighRes.png | Bin 0 -> 4060 bytes matrixConsole/Assets/matrixConsole.jpg | Bin 0 -> 22884 bytes matrixConsole/Assets/play.png | Bin 0 -> 1638 bytes matrixConsole/Assets/tab_home.ico | Bin 0 -> 198 bytes matrixConsole/Assets/tab_recents.png | Bin 0 -> 1890 bytes matrixConsole/Assets/tab_recents@2x.png | Bin 0 -> 1890 bytes matrixConsole/Base.lproj/LaunchScreen.xib | 35 + matrixConsole/Base.lproj/Main.storyboard | 1064 ++++++++++ matrixConsole/CustomAlert.h | 53 + matrixConsole/CustomAlert.m | 210 ++ .../AppIcon.appiconset/Contents.json | 122 ++ .../AppIcon.appiconset/Icon-29-1.png | Bin 0 -> 4015 bytes .../AppIcon.appiconset/Icon-29.png | Bin 0 -> 4015 bytes .../AppIcon.appiconset/Icon-29@2x-1.png | Bin 0 -> 5233 bytes .../AppIcon.appiconset/Icon-29@2x.png | Bin 0 -> 5233 bytes .../AppIcon.appiconset/Icon-29@3x.png | Bin 0 -> 6495 bytes .../AppIcon.appiconset/Icon-40.png | Bin 0 -> 4465 bytes .../AppIcon.appiconset/Icon-40@2x-1.png | Bin 0 -> 6157 bytes .../AppIcon.appiconset/Icon-40@2x.png | Bin 0 -> 6157 bytes .../AppIcon.appiconset/Icon-40@3x.png | Bin 0 -> 8401 bytes .../AppIcon.appiconset/Icon-50.png | Bin 0 -> 4888 bytes .../AppIcon.appiconset/Icon-50@2x.png | Bin 0 -> 7164 bytes .../AppIcon.appiconset/Icon-57.png | Bin 0 -> 5249 bytes .../AppIcon.appiconset/Icon-57@2x.png | Bin 0 -> 8094 bytes .../AppIcon.appiconset/Icon-60@2x.png | Bin 0 -> 8401 bytes .../AppIcon.appiconset/Icon-60@3x.png | Bin 0 -> 11463 bytes .../AppIcon.appiconset/Icon-72.png | Bin 0 -> 5735 bytes .../AppIcon.appiconset/Icon-72@2x.png | Bin 0 -> 9430 bytes .../AppIcon.appiconset/Icon-76.png | Bin 0 -> 6096 bytes .../AppIcon.appiconset/Icon-76@2x.png | Bin 0 -> 9983 bytes .../LaunchImage.launchimage/Contents.json | 107 + .../Default-Landscape.png | Bin 0 -> 33325 bytes .../Default-Landscape@2x.png | Bin 0 -> 74252 bytes .../Default-Landscape@2x~ipad.png | Bin 0 -> 76052 bytes .../Default-Landscape~ipad.png | Bin 0 -> 33543 bytes .../Default-Portrait.png | Bin 0 -> 33927 bytes .../Default-Portrait@2x.png | Bin 0 -> 76962 bytes .../Default-Portrait@2x~ipad.png | Bin 0 -> 77394 bytes .../Default-Portrait~ipad.png | Bin 0 -> 34198 bytes .../launch-568h@2x-1.png | Bin 0 -> 30909 bytes .../launch-568h@2x.png | Bin 0 -> 30909 bytes .../LaunchImage.launchimage/launch.png | Bin 0 -> 19797 bytes .../LaunchImage.launchimage/launch@2x-1.png | Bin 0 -> 28058 bytes .../LaunchImage.launchimage/launch@2x.png | Bin 0 -> 28058 bytes matrixConsole/Info.plist | 57 + matrixConsole/MatrixHandler.h | 52 + matrixConsole/MatrixHandler.m | 629 ++++++ matrixConsole/MediaManager.h | 50 + matrixConsole/MediaManager.m | 327 +++ matrixConsole/View/CustomImageView.h | 27 + matrixConsole/View/CustomImageView.m | 82 + matrixConsole/View/RecentsTableViewCell.h | 25 + matrixConsole/View/RecentsTableViewCell.m | 20 + matrixConsole/View/RoomMemberTableCell.h | 32 + matrixConsole/View/RoomMemberTableCell.m | 148 ++ matrixConsole/View/RoomMessageTableCell.h | 44 + matrixConsole/View/RoomMessageTableCell.m | 29 + matrixConsole/View/SettingsTableViewCell.h | 29 + matrixConsole/View/SettingsTableViewCell.m | 26 + .../ViewController/HomeViewController.h | 22 + .../ViewController/HomeViewController.m | 386 ++++ .../ViewController/LoginViewController.h | 22 + .../ViewController/LoginViewController.m | 226 ++ .../ViewController/MasterTabBarController.h | 36 + .../ViewController/MasterTabBarController.m | 137 ++ .../ViewController/RecentsViewController.h | 26 + .../ViewController/RecentsViewController.m | 311 +++ .../ViewController/RoomViewController.h | 24 + .../ViewController/RoomViewController.m | 1834 +++++++++++++++++ .../ViewController/SettingsViewController.h | 24 + .../ViewController/SettingsViewController.m | 517 +++++ matrixConsole/main.m | 24 + matrixConsoleTests/Info.plist | 24 + matrixConsoleTests/matrixConsoleTests.m | 48 + 87 files changed, 7854 insertions(+) create mode 100644 .gitignore create mode 100644 Podfile create mode 100644 Podfile.lock create mode 100644 README.rst create mode 100644 matrixConsole.xcodeproj/project.pbxproj create mode 100644 matrixConsole/AppDelegate.h create mode 100644 matrixConsole/AppDelegate.m create mode 100644 matrixConsole/AppSettings.h create mode 100644 matrixConsole/AppSettings.m create mode 100644 matrixConsole/Assets/close.png create mode 100644 matrixConsole/Assets/default-profile.png create mode 100644 matrixConsole/Assets/gradient.png create mode 100644 matrixConsole/Assets/logo.png create mode 100644 matrixConsole/Assets/logoHighRes.png create mode 100644 matrixConsole/Assets/matrixConsole.jpg create mode 100755 matrixConsole/Assets/play.png create mode 100644 matrixConsole/Assets/tab_home.ico create mode 100644 matrixConsole/Assets/tab_recents.png create mode 100644 matrixConsole/Assets/tab_recents@2x.png create mode 100644 matrixConsole/Base.lproj/LaunchScreen.xib create mode 100644 matrixConsole/Base.lproj/Main.storyboard create mode 100644 matrixConsole/CustomAlert.h create mode 100644 matrixConsole/CustomAlert.m create mode 100644 matrixConsole/Images.xcassets/AppIcon.appiconset/Contents.json create mode 100644 matrixConsole/Images.xcassets/AppIcon.appiconset/Icon-29-1.png create mode 100644 matrixConsole/Images.xcassets/AppIcon.appiconset/Icon-29.png create mode 100644 matrixConsole/Images.xcassets/AppIcon.appiconset/Icon-29@2x-1.png create mode 100644 matrixConsole/Images.xcassets/AppIcon.appiconset/Icon-29@2x.png create mode 100644 matrixConsole/Images.xcassets/AppIcon.appiconset/Icon-29@3x.png create mode 100644 matrixConsole/Images.xcassets/AppIcon.appiconset/Icon-40.png create mode 100644 matrixConsole/Images.xcassets/AppIcon.appiconset/Icon-40@2x-1.png create mode 100644 matrixConsole/Images.xcassets/AppIcon.appiconset/Icon-40@2x.png create mode 100644 matrixConsole/Images.xcassets/AppIcon.appiconset/Icon-40@3x.png create mode 100644 matrixConsole/Images.xcassets/AppIcon.appiconset/Icon-50.png create mode 100644 matrixConsole/Images.xcassets/AppIcon.appiconset/Icon-50@2x.png create mode 100644 matrixConsole/Images.xcassets/AppIcon.appiconset/Icon-57.png create mode 100644 matrixConsole/Images.xcassets/AppIcon.appiconset/Icon-57@2x.png create mode 100644 matrixConsole/Images.xcassets/AppIcon.appiconset/Icon-60@2x.png create mode 100644 matrixConsole/Images.xcassets/AppIcon.appiconset/Icon-60@3x.png create mode 100644 matrixConsole/Images.xcassets/AppIcon.appiconset/Icon-72.png create mode 100644 matrixConsole/Images.xcassets/AppIcon.appiconset/Icon-72@2x.png create mode 100644 matrixConsole/Images.xcassets/AppIcon.appiconset/Icon-76.png create mode 100644 matrixConsole/Images.xcassets/AppIcon.appiconset/Icon-76@2x.png create mode 100644 matrixConsole/Images.xcassets/LaunchImage.launchimage/Contents.json create mode 100644 matrixConsole/Images.xcassets/LaunchImage.launchimage/Default-Landscape.png create mode 100644 matrixConsole/Images.xcassets/LaunchImage.launchimage/Default-Landscape@2x.png create mode 100644 matrixConsole/Images.xcassets/LaunchImage.launchimage/Default-Landscape@2x~ipad.png create mode 100644 matrixConsole/Images.xcassets/LaunchImage.launchimage/Default-Landscape~ipad.png create mode 100644 matrixConsole/Images.xcassets/LaunchImage.launchimage/Default-Portrait.png create mode 100644 matrixConsole/Images.xcassets/LaunchImage.launchimage/Default-Portrait@2x.png create mode 100644 matrixConsole/Images.xcassets/LaunchImage.launchimage/Default-Portrait@2x~ipad.png create mode 100644 matrixConsole/Images.xcassets/LaunchImage.launchimage/Default-Portrait~ipad.png create mode 100644 matrixConsole/Images.xcassets/LaunchImage.launchimage/launch-568h@2x-1.png create mode 100644 matrixConsole/Images.xcassets/LaunchImage.launchimage/launch-568h@2x.png create mode 100644 matrixConsole/Images.xcassets/LaunchImage.launchimage/launch.png create mode 100644 matrixConsole/Images.xcassets/LaunchImage.launchimage/launch@2x-1.png create mode 100644 matrixConsole/Images.xcassets/LaunchImage.launchimage/launch@2x.png create mode 100644 matrixConsole/Info.plist create mode 100644 matrixConsole/MatrixHandler.h create mode 100644 matrixConsole/MatrixHandler.m create mode 100644 matrixConsole/MediaManager.h create mode 100644 matrixConsole/MediaManager.m create mode 100644 matrixConsole/View/CustomImageView.h create mode 100644 matrixConsole/View/CustomImageView.m create mode 100644 matrixConsole/View/RecentsTableViewCell.h create mode 100644 matrixConsole/View/RecentsTableViewCell.m create mode 100644 matrixConsole/View/RoomMemberTableCell.h create mode 100644 matrixConsole/View/RoomMemberTableCell.m create mode 100644 matrixConsole/View/RoomMessageTableCell.h create mode 100644 matrixConsole/View/RoomMessageTableCell.m create mode 100644 matrixConsole/View/SettingsTableViewCell.h create mode 100644 matrixConsole/View/SettingsTableViewCell.m create mode 100644 matrixConsole/ViewController/HomeViewController.h create mode 100644 matrixConsole/ViewController/HomeViewController.m create mode 100644 matrixConsole/ViewController/LoginViewController.h create mode 100644 matrixConsole/ViewController/LoginViewController.m create mode 100644 matrixConsole/ViewController/MasterTabBarController.h create mode 100644 matrixConsole/ViewController/MasterTabBarController.m create mode 100644 matrixConsole/ViewController/RecentsViewController.h create mode 100644 matrixConsole/ViewController/RecentsViewController.m create mode 100644 matrixConsole/ViewController/RoomViewController.h create mode 100644 matrixConsole/ViewController/RoomViewController.m create mode 100644 matrixConsole/ViewController/SettingsViewController.h create mode 100644 matrixConsole/ViewController/SettingsViewController.m create mode 100644 matrixConsole/main.m create mode 100644 matrixConsoleTests/Info.plist create mode 100644 matrixConsoleTests/matrixConsoleTests.m diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..e0217c405 --- /dev/null +++ b/.gitignore @@ -0,0 +1,29 @@ +# Xcode +# +build/ +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +xcuserdata +*.xccheckout +*.moved-aside +DerivedData +*.hmap +*.ipa +*.xcuserstate + +# CocoaPods +# +# We recommend against adding the Pods directory to your .gitignore. However +# you should judge for yourself, the pros and cons are mentioned at: +# http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control +# +Pods/ + +# Do not track our workspace since it is created by CocoaPods +*.xcworkspace diff --git a/Podfile b/Podfile new file mode 100644 index 000000000..15bb881f1 --- /dev/null +++ b/Podfile @@ -0,0 +1,16 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, "6.0" + +source 'https://github.com/CocoaPods/Specs.git' + +target "matrixConsole" do + +# Points to SDK local sources file +pod 'MatrixSDK', :path => '../../MatrixSDK.podspec' + +end + +target "matrixConsole" do + +end + diff --git a/Podfile.lock b/Podfile.lock new file mode 100644 index 000000000..672f5f741 --- /dev/null +++ b/Podfile.lock @@ -0,0 +1,42 @@ +PODS: + - AFNetworking (2.4.1): + - AFNetworking/NSURLConnection + - AFNetworking/NSURLSession + - AFNetworking/Reachability + - AFNetworking/Security + - AFNetworking/Serialization + - AFNetworking/UIKit + - AFNetworking/NSURLConnection (2.4.1): + - AFNetworking/Reachability + - AFNetworking/Security + - AFNetworking/Serialization + - AFNetworking/NSURLSession (2.4.1): + - AFNetworking/Reachability + - AFNetworking/Security + - AFNetworking/Serialization + - AFNetworking/Reachability (2.4.1) + - AFNetworking/Security (2.4.1) + - AFNetworking/Serialization (2.4.1) + - AFNetworking/UIKit (2.4.1): + - AFNetworking/NSURLConnection + - AFNetworking/NSURLSession + - Mantle (1.5.1): + - Mantle/extobjc + - Mantle/extobjc (1.5.1) + - MatrixSDK (0.0.1): + - AFNetworking (~> 2.4.1) + - Mantle (~> 1.5) + +DEPENDENCIES: + - MatrixSDK (from `../../MatrixSDK.podspec`) + +EXTERNAL SOURCES: + MatrixSDK: + :path: ../../MatrixSDK.podspec + +SPEC CHECKSUMS: + AFNetworking: 0aabc6fae66d6e5d039eeb21c315843c7aae51ab + Mantle: d7c5ac734579ec751c58fecbf56189853056c58c + MatrixSDK: 42aac6ed0123d5339f27e3f57d8972edf17f8224 + +COCOAPODS: 0.34.1 diff --git a/README.rst b/README.rst new file mode 100644 index 000000000..c3c3070f2 --- /dev/null +++ b/README.rst @@ -0,0 +1,11 @@ +Build instructions +================== + +Before opening the sample workspace, you need to build it with the CocoaPods command:: + + $ pod install + +This will load your local SDK source code into the sample workspace. + + +Then, open ``syMessaging.xcworkspace``. diff --git a/matrixConsole.xcodeproj/project.pbxproj b/matrixConsole.xcodeproj/project.pbxproj new file mode 100644 index 000000000..5ce5285dc --- /dev/null +++ b/matrixConsole.xcodeproj/project.pbxproj @@ -0,0 +1,640 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + D648B86A591308736E2D4078 /* libPods-matrixConsole.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8141B1E2401FFCC3C5B99234 /* libPods-matrixConsole.a */; }; + F00B5DB91A1B9BCE00EA1C8D /* CustomImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = F00B5DB81A1B9BCE00EA1C8D /* CustomImageView.m */; }; + F01628C119E29C660071C473 /* default-profile.png in Resources */ = {isa = PBXBuildFile; fileRef = F01628BC19E29C660071C473 /* default-profile.png */; }; + F01628C319E29C660071C473 /* logo.png in Resources */ = {isa = PBXBuildFile; fileRef = F01628BE19E29C660071C473 /* logo.png */; }; + F024098219E7D177006E741B /* tab_recents@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = F024098119E7D177006E741B /* tab_recents@2x.png */; }; + F02BCE231A1A5A2B00543B47 /* play.png in Resources */ = {isa = PBXBuildFile; fileRef = F02BCE221A1A5A2B00543B47 /* play.png */; }; + F02D707619F1DC9E007B47D3 /* RoomMemberTableCell.m in Sources */ = {isa = PBXBuildFile; fileRef = F02D707519F1DC9E007B47D3 /* RoomMemberTableCell.m */; }; + F03C47111A02952800E445AB /* CustomAlert.m in Sources */ = {isa = PBXBuildFile; fileRef = F03C47101A02952800E445AB /* CustomAlert.m */; }; + F03EF5F619F171EB00A0EE52 /* HomeViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = F03EF5EB19F171EB00A0EE52 /* HomeViewController.m */; }; + F03EF5F719F171EB00A0EE52 /* LoginViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = F03EF5ED19F171EB00A0EE52 /* LoginViewController.m */; }; + F03EF5F819F171EB00A0EE52 /* MasterTabBarController.m in Sources */ = {isa = PBXBuildFile; fileRef = F03EF5EF19F171EB00A0EE52 /* MasterTabBarController.m */; }; + F03EF5F919F171EB00A0EE52 /* RecentsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = F03EF5F119F171EB00A0EE52 /* RecentsViewController.m */; }; + F03EF5FA19F171EB00A0EE52 /* RoomViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = F03EF5F319F171EB00A0EE52 /* RoomViewController.m */; }; + F03EF5FB19F171EB00A0EE52 /* SettingsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = F03EF5F519F171EB00A0EE52 /* SettingsViewController.m */; }; + F03EF5FF19F1762000A0EE52 /* RoomMessageTableCell.m in Sources */ = {isa = PBXBuildFile; fileRef = F03EF5FE19F1762000A0EE52 /* RoomMessageTableCell.m */; }; + F03EF60219F19E7C00A0EE52 /* MediaManager.m in Sources */ = {isa = PBXBuildFile; fileRef = F03EF60119F19E7C00A0EE52 /* MediaManager.m */; }; + F05B955F19DEED8A008761B0 /* MatrixHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = F05B955E19DEED8A008761B0 /* MatrixHandler.m */; }; + F07A80D819DD9DE700B621A1 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = F07A80D719DD9DE700B621A1 /* main.m */; }; + F07A80DB19DD9DE700B621A1 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = F07A80DA19DD9DE700B621A1 /* AppDelegate.m */; }; + F07A80E419DD9DE700B621A1 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F07A80E219DD9DE700B621A1 /* Main.storyboard */; }; + F07A80E619DD9DE700B621A1 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F07A80E519DD9DE700B621A1 /* Images.xcassets */; }; + F07A80E919DD9DE700B621A1 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = F07A80E719DD9DE700B621A1 /* LaunchScreen.xib */; }; + F07A80F519DD9DE700B621A1 /* syMessagingTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F07A80F419DD9DE700B621A1 /* syMessagingTests.m */; }; + F08B6FCC1A1DE7F80094A35B /* matrixConsole.jpg in Resources */ = {isa = PBXBuildFile; fileRef = F08B6FCB1A1DE7F80094A35B /* matrixConsole.jpg */; }; + F08DCBDB1A093BFA008C65B6 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F08DCBDA1A093BFA008C65B6 /* MobileCoreServices.framework */; }; + F0CEA5AE19E6895E00E47915 /* logoHighRes.png in Resources */ = {isa = PBXBuildFile; fileRef = F0CEA5AC19E6895E00E47915 /* logoHighRes.png */; }; + F0CEA5AF19E6895E00E47915 /* tab_recents.png in Resources */ = {isa = PBXBuildFile; fileRef = F0CEA5AD19E6895E00E47915 /* tab_recents.png */; }; + F0CEA5B119E6898800E47915 /* tab_home.ico in Resources */ = {isa = PBXBuildFile; fileRef = F0CEA5B019E6898800E47915 /* tab_home.ico */; }; + F0D3C30C1A011EF10000D49E /* AppSettings.m in Sources */ = {isa = PBXBuildFile; fileRef = F0D3C30B1A011EF10000D49E /* AppSettings.m */; }; + F0D3C30F1A01330F0000D49E /* SettingsTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = F0D3C30E1A01330F0000D49E /* SettingsTableViewCell.m */; }; + F0E84D401A1F9AEC005F2E42 /* RecentsTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = F0E84D3F1A1F9AEC005F2E42 /* RecentsTableViewCell.m */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + F07A80EF19DD9DE700B621A1 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = F07A80CA19DD9DE700B621A1 /* Project object */; + proxyType = 1; + remoteGlobalIDString = F07A80D119DD9DE700B621A1; + remoteInfo = syMessaging; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 13057A57E74FD5504196F47F /* Pods-matrixConsole.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-matrixConsole.release.xcconfig"; path = "Pods/Target Support Files/Pods-matrixConsole/Pods-matrixConsole.release.xcconfig"; sourceTree = ""; }; + 8141B1E2401FFCC3C5B99234 /* libPods-matrixConsole.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-matrixConsole.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + B7EC7E45C718BF2BBCE0CF48 /* Pods-matrixConsole.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-matrixConsole.debug.xcconfig"; path = "Pods/Target Support Files/Pods-matrixConsole/Pods-matrixConsole.debug.xcconfig"; sourceTree = ""; }; + F00B5DB71A1B9BCE00EA1C8D /* CustomImageView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CustomImageView.h; sourceTree = ""; }; + F00B5DB81A1B9BCE00EA1C8D /* CustomImageView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CustomImageView.m; sourceTree = ""; }; + F01628BC19E29C660071C473 /* default-profile.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "default-profile.png"; sourceTree = ""; }; + F01628BE19E29C660071C473 /* logo.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = logo.png; sourceTree = ""; }; + F024098119E7D177006E741B /* tab_recents@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "tab_recents@2x.png"; sourceTree = ""; }; + F02BCE221A1A5A2B00543B47 /* play.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = play.png; sourceTree = ""; }; + F02D707419F1DC9E007B47D3 /* RoomMemberTableCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RoomMemberTableCell.h; sourceTree = ""; }; + F02D707519F1DC9E007B47D3 /* RoomMemberTableCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RoomMemberTableCell.m; sourceTree = ""; }; + F03C470F1A02952800E445AB /* CustomAlert.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CustomAlert.h; sourceTree = ""; }; + F03C47101A02952800E445AB /* CustomAlert.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CustomAlert.m; sourceTree = ""; }; + F03EF5EA19F171EB00A0EE52 /* HomeViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HomeViewController.h; sourceTree = ""; }; + F03EF5EB19F171EB00A0EE52 /* HomeViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HomeViewController.m; sourceTree = ""; }; + F03EF5EC19F171EB00A0EE52 /* LoginViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LoginViewController.h; sourceTree = ""; }; + F03EF5ED19F171EB00A0EE52 /* LoginViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LoginViewController.m; sourceTree = ""; }; + F03EF5EE19F171EB00A0EE52 /* MasterTabBarController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MasterTabBarController.h; sourceTree = ""; }; + F03EF5EF19F171EB00A0EE52 /* MasterTabBarController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MasterTabBarController.m; sourceTree = ""; }; + F03EF5F019F171EB00A0EE52 /* RecentsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RecentsViewController.h; sourceTree = ""; }; + F03EF5F119F171EB00A0EE52 /* RecentsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RecentsViewController.m; sourceTree = ""; }; + F03EF5F219F171EB00A0EE52 /* RoomViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RoomViewController.h; sourceTree = ""; }; + F03EF5F319F171EB00A0EE52 /* RoomViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RoomViewController.m; sourceTree = ""; }; + F03EF5F419F171EB00A0EE52 /* SettingsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SettingsViewController.h; sourceTree = ""; }; + F03EF5F519F171EB00A0EE52 /* SettingsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SettingsViewController.m; sourceTree = ""; }; + F03EF5FD19F1762000A0EE52 /* RoomMessageTableCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RoomMessageTableCell.h; sourceTree = ""; }; + F03EF5FE19F1762000A0EE52 /* RoomMessageTableCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RoomMessageTableCell.m; sourceTree = ""; }; + F03EF60019F19E7C00A0EE52 /* MediaManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MediaManager.h; sourceTree = ""; }; + F03EF60119F19E7C00A0EE52 /* MediaManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MediaManager.m; sourceTree = ""; }; + F05B955D19DEED8A008761B0 /* MatrixHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MatrixHandler.h; sourceTree = ""; }; + F05B955E19DEED8A008761B0 /* MatrixHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MatrixHandler.m; sourceTree = ""; }; + F07A80D219DD9DE700B621A1 /* matrixConsole.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = matrixConsole.app; sourceTree = BUILT_PRODUCTS_DIR; }; + F07A80D619DD9DE700B621A1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + F07A80D719DD9DE700B621A1 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + F07A80D919DD9DE700B621A1 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; + F07A80DA19DD9DE700B621A1 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + F07A80E319DD9DE700B621A1 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + F07A80E519DD9DE700B621A1 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; + F07A80E819DD9DE700B621A1 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; + F07A80EE19DD9DE700B621A1 /* matrixConsoleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = matrixConsoleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + F07A80F319DD9DE700B621A1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + F07A80F419DD9DE700B621A1 /* syMessagingTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = syMessagingTests.m; sourceTree = ""; }; + F08B6FCB1A1DE7F80094A35B /* matrixConsole.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = matrixConsole.jpg; sourceTree = ""; }; + F08DCBDA1A093BFA008C65B6 /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = System/Library/Frameworks/MobileCoreServices.framework; sourceTree = SDKROOT; }; + F0CEA5AC19E6895E00E47915 /* logoHighRes.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = logoHighRes.png; sourceTree = ""; }; + F0CEA5AD19E6895E00E47915 /* tab_recents.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = tab_recents.png; sourceTree = ""; }; + F0CEA5B019E6898800E47915 /* tab_home.ico */ = {isa = PBXFileReference; lastKnownFileType = image.ico; path = tab_home.ico; sourceTree = ""; }; + F0D3C30A1A011EF10000D49E /* AppSettings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppSettings.h; sourceTree = ""; }; + F0D3C30B1A011EF10000D49E /* AppSettings.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppSettings.m; sourceTree = ""; }; + F0D3C30D1A01330F0000D49E /* SettingsTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SettingsTableViewCell.h; sourceTree = ""; }; + F0D3C30E1A01330F0000D49E /* SettingsTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SettingsTableViewCell.m; sourceTree = ""; }; + F0E84D3E1A1F9AEC005F2E42 /* RecentsTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RecentsTableViewCell.h; sourceTree = ""; }; + F0E84D3F1A1F9AEC005F2E42 /* RecentsTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RecentsTableViewCell.m; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + F07A80CF19DD9DE700B621A1 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + F08DCBDB1A093BFA008C65B6 /* MobileCoreServices.framework in Frameworks */, + D648B86A591308736E2D4078 /* libPods-matrixConsole.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F07A80EB19DD9DE700B621A1 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + B18A10A9FB884DD357EBD414 /* Pods */ = { + isa = PBXGroup; + children = ( + B7EC7E45C718BF2BBCE0CF48 /* Pods-matrixConsole.debug.xcconfig */, + 13057A57E74FD5504196F47F /* Pods-matrixConsole.release.xcconfig */, + ); + name = Pods; + sourceTree = ""; + }; + EAA71E3C2B16D1D86B3F5100 /* Frameworks */ = { + isa = PBXGroup; + children = ( + F08DCBDA1A093BFA008C65B6 /* MobileCoreServices.framework */, + 8141B1E2401FFCC3C5B99234 /* libPods-matrixConsole.a */, + ); + name = Frameworks; + sourceTree = ""; + }; + F01628B519E298710071C473 /* Assets */ = { + isa = PBXGroup; + children = ( + F08B6FCB1A1DE7F80094A35B /* matrixConsole.jpg */, + F02BCE221A1A5A2B00543B47 /* play.png */, + F024098119E7D177006E741B /* tab_recents@2x.png */, + F0CEA5B019E6898800E47915 /* tab_home.ico */, + F0CEA5AD19E6895E00E47915 /* tab_recents.png */, + F01628BC19E29C660071C473 /* default-profile.png */, + F01628BE19E29C660071C473 /* logo.png */, + F0CEA5AC19E6895E00E47915 /* logoHighRes.png */, + ); + path = Assets; + sourceTree = ""; + }; + F03EF5E919F171EB00A0EE52 /* ViewController */ = { + isa = PBXGroup; + children = ( + F03EF5EA19F171EB00A0EE52 /* HomeViewController.h */, + F03EF5EB19F171EB00A0EE52 /* HomeViewController.m */, + F03EF5EC19F171EB00A0EE52 /* LoginViewController.h */, + F03EF5ED19F171EB00A0EE52 /* LoginViewController.m */, + F03EF5EE19F171EB00A0EE52 /* MasterTabBarController.h */, + F03EF5EF19F171EB00A0EE52 /* MasterTabBarController.m */, + F03EF5F019F171EB00A0EE52 /* RecentsViewController.h */, + F03EF5F119F171EB00A0EE52 /* RecentsViewController.m */, + F03EF5F219F171EB00A0EE52 /* RoomViewController.h */, + F03EF5F319F171EB00A0EE52 /* RoomViewController.m */, + F03EF5F419F171EB00A0EE52 /* SettingsViewController.h */, + F03EF5F519F171EB00A0EE52 /* SettingsViewController.m */, + ); + path = ViewController; + sourceTree = ""; + }; + F03EF5FC19F1762000A0EE52 /* View */ = { + isa = PBXGroup; + children = ( + F00B5DB71A1B9BCE00EA1C8D /* CustomImageView.h */, + F00B5DB81A1B9BCE00EA1C8D /* CustomImageView.m */, + F0E84D3E1A1F9AEC005F2E42 /* RecentsTableViewCell.h */, + F0E84D3F1A1F9AEC005F2E42 /* RecentsTableViewCell.m */, + F02D707419F1DC9E007B47D3 /* RoomMemberTableCell.h */, + F02D707519F1DC9E007B47D3 /* RoomMemberTableCell.m */, + F03EF5FD19F1762000A0EE52 /* RoomMessageTableCell.h */, + F03EF5FE19F1762000A0EE52 /* RoomMessageTableCell.m */, + F0D3C30D1A01330F0000D49E /* SettingsTableViewCell.h */, + F0D3C30E1A01330F0000D49E /* SettingsTableViewCell.m */, + ); + path = View; + sourceTree = ""; + }; + F07A80C919DD9DE700B621A1 = { + isa = PBXGroup; + children = ( + F07A80D419DD9DE700B621A1 /* syMessaging */, + F07A80F119DD9DE700B621A1 /* syMessagingTests */, + F07A80D319DD9DE700B621A1 /* Products */, + B18A10A9FB884DD357EBD414 /* Pods */, + EAA71E3C2B16D1D86B3F5100 /* Frameworks */, + ); + sourceTree = ""; + }; + F07A80D319DD9DE700B621A1 /* Products */ = { + isa = PBXGroup; + children = ( + F07A80D219DD9DE700B621A1 /* matrixConsole.app */, + F07A80EE19DD9DE700B621A1 /* matrixConsoleTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + F07A80D419DD9DE700B621A1 /* syMessaging */ = { + isa = PBXGroup; + children = ( + F03EF5FC19F1762000A0EE52 /* View */, + F03EF5E919F171EB00A0EE52 /* ViewController */, + F07A80D919DD9DE700B621A1 /* AppDelegate.h */, + F07A80DA19DD9DE700B621A1 /* AppDelegate.m */, + F0D3C30A1A011EF10000D49E /* AppSettings.h */, + F0D3C30B1A011EF10000D49E /* AppSettings.m */, + F03C470F1A02952800E445AB /* CustomAlert.h */, + F03C47101A02952800E445AB /* CustomAlert.m */, + F05B955D19DEED8A008761B0 /* MatrixHandler.h */, + F05B955E19DEED8A008761B0 /* MatrixHandler.m */, + F03EF60019F19E7C00A0EE52 /* MediaManager.h */, + F03EF60119F19E7C00A0EE52 /* MediaManager.m */, + F07A80E219DD9DE700B621A1 /* Main.storyboard */, + F07A80E519DD9DE700B621A1 /* Images.xcassets */, + F07A80E719DD9DE700B621A1 /* LaunchScreen.xib */, + F01628B519E298710071C473 /* Assets */, + F07A80D519DD9DE700B621A1 /* Supporting Files */, + ); + path = syMessaging; + sourceTree = ""; + }; + F07A80D519DD9DE700B621A1 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + F07A80D619DD9DE700B621A1 /* Info.plist */, + F07A80D719DD9DE700B621A1 /* main.m */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + F07A80F119DD9DE700B621A1 /* syMessagingTests */ = { + isa = PBXGroup; + children = ( + F07A80F419DD9DE700B621A1 /* syMessagingTests.m */, + F07A80F219DD9DE700B621A1 /* Supporting Files */, + ); + path = syMessagingTests; + sourceTree = ""; + }; + F07A80F219DD9DE700B621A1 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + F07A80F319DD9DE700B621A1 /* Info.plist */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + F07A80D119DD9DE700B621A1 /* matrixConsole */ = { + isa = PBXNativeTarget; + buildConfigurationList = F07A80F819DD9DE700B621A1 /* Build configuration list for PBXNativeTarget "matrixConsole" */; + buildPhases = ( + A063750719371855C7755702 /* Check Pods Manifest.lock */, + F07A80CE19DD9DE700B621A1 /* Sources */, + F07A80CF19DD9DE700B621A1 /* Frameworks */, + F07A80D019DD9DE700B621A1 /* Resources */, + 3496B335A95D95AB2A8DCEF4 /* Copy Pods Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = matrixConsole; + productName = syMessaging; + productReference = F07A80D219DD9DE700B621A1 /* matrixConsole.app */; + productType = "com.apple.product-type.application"; + }; + F07A80ED19DD9DE700B621A1 /* matrixConsoleTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = F07A80FB19DD9DE700B621A1 /* Build configuration list for PBXNativeTarget "matrixConsoleTests" */; + buildPhases = ( + F07A80EA19DD9DE700B621A1 /* Sources */, + F07A80EB19DD9DE700B621A1 /* Frameworks */, + F07A80EC19DD9DE700B621A1 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + F07A80F019DD9DE700B621A1 /* PBXTargetDependency */, + ); + name = matrixConsoleTests; + productName = syMessagingTests; + productReference = F07A80EE19DD9DE700B621A1 /* matrixConsoleTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + F07A80CA19DD9DE700B621A1 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0600; + ORGANIZATIONNAME = matrix.org; + TargetAttributes = { + F07A80D119DD9DE700B621A1 = { + CreatedOnToolsVersion = 6.0; + }; + F07A80ED19DD9DE700B621A1 = { + CreatedOnToolsVersion = 6.0; + TestTargetID = F07A80D119DD9DE700B621A1; + }; + }; + }; + buildConfigurationList = F07A80CD19DD9DE700B621A1 /* Build configuration list for PBXProject "matrixConsole" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = F07A80C919DD9DE700B621A1; + productRefGroup = F07A80D319DD9DE700B621A1 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + F07A80D119DD9DE700B621A1 /* matrixConsole */, + F07A80ED19DD9DE700B621A1 /* matrixConsoleTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + F07A80D019DD9DE700B621A1 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + F024098219E7D177006E741B /* tab_recents@2x.png in Resources */, + F02BCE231A1A5A2B00543B47 /* play.png in Resources */, + F07A80E419DD9DE700B621A1 /* Main.storyboard in Resources */, + F07A80E919DD9DE700B621A1 /* LaunchScreen.xib in Resources */, + F0CEA5AF19E6895E00E47915 /* tab_recents.png in Resources */, + F01628C319E29C660071C473 /* logo.png in Resources */, + F01628C119E29C660071C473 /* default-profile.png in Resources */, + F0CEA5AE19E6895E00E47915 /* logoHighRes.png in Resources */, + F0CEA5B119E6898800E47915 /* tab_home.ico in Resources */, + F07A80E619DD9DE700B621A1 /* Images.xcassets in Resources */, + F08B6FCC1A1DE7F80094A35B /* matrixConsole.jpg in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F07A80EC19DD9DE700B621A1 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3496B335A95D95AB2A8DCEF4 /* Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Copy Pods Resources"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-matrixConsole/Pods-matrixConsole-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + A063750719371855C7755702 /* Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Check Pods Manifest.lock"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + F07A80CE19DD9DE700B621A1 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + F07A80DB19DD9DE700B621A1 /* AppDelegate.m in Sources */, + F03EF5FF19F1762000A0EE52 /* RoomMessageTableCell.m in Sources */, + F07A80D819DD9DE700B621A1 /* main.m in Sources */, + F05B955F19DEED8A008761B0 /* MatrixHandler.m in Sources */, + F03EF5FB19F171EB00A0EE52 /* SettingsViewController.m in Sources */, + F03EF5FA19F171EB00A0EE52 /* RoomViewController.m in Sources */, + F03EF5F819F171EB00A0EE52 /* MasterTabBarController.m in Sources */, + F03EF5F619F171EB00A0EE52 /* HomeViewController.m in Sources */, + F03EF60219F19E7C00A0EE52 /* MediaManager.m in Sources */, + F03EF5F919F171EB00A0EE52 /* RecentsViewController.m in Sources */, + F03C47111A02952800E445AB /* CustomAlert.m in Sources */, + F0E84D401A1F9AEC005F2E42 /* RecentsTableViewCell.m in Sources */, + F02D707619F1DC9E007B47D3 /* RoomMemberTableCell.m in Sources */, + F00B5DB91A1B9BCE00EA1C8D /* CustomImageView.m in Sources */, + F0D3C30C1A011EF10000D49E /* AppSettings.m in Sources */, + F03EF5F719F171EB00A0EE52 /* LoginViewController.m in Sources */, + F0D3C30F1A01330F0000D49E /* SettingsTableViewCell.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F07A80EA19DD9DE700B621A1 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + F07A80F519DD9DE700B621A1 /* syMessagingTests.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + F07A80F019DD9DE700B621A1 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = F07A80D119DD9DE700B621A1 /* matrixConsole */; + targetProxy = F07A80EF19DD9DE700B621A1 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + F07A80E219DD9DE700B621A1 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + F07A80E319DD9DE700B621A1 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + F07A80E719DD9DE700B621A1 /* LaunchScreen.xib */ = { + isa = PBXVariantGroup; + children = ( + F07A80E819DD9DE700B621A1 /* Base */, + ); + name = LaunchScreen.xib; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + F07A80F619DD9DE700B621A1 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + F07A80F719DD9DE700B621A1 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = YES; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + F07A80F919DD9DE700B621A1 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = B7EC7E45C718BF2BBCE0CF48 /* Pods-matrixConsole.debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; + INFOPLIST_FILE = syMessaging/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 6.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_NAME = matrixConsole; + }; + name = Debug; + }; + F07A80FA19DD9DE700B621A1 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 13057A57E74FD5504196F47F /* Pods-matrixConsole.release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; + INFOPLIST_FILE = syMessaging/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 6.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_NAME = matrixConsole; + }; + name = Release; + }; + F07A80FC19DD9DE700B621A1 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + FRAMEWORK_SEARCH_PATHS = ( + "$(SDKROOT)/Developer/Library/Frameworks", + "$(inherited)", + ); + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + INFOPLIST_FILE = syMessagingTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_NAME = matrixConsoleTests; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/matrixConsole.app/matrixConsole"; + }; + name = Debug; + }; + F07A80FD19DD9DE700B621A1 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + FRAMEWORK_SEARCH_PATHS = ( + "$(SDKROOT)/Developer/Library/Frameworks", + "$(inherited)", + ); + INFOPLIST_FILE = syMessagingTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_NAME = matrixConsoleTests; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/matrixConsole.app/matrixConsole"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + F07A80CD19DD9DE700B621A1 /* Build configuration list for PBXProject "matrixConsole" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + F07A80F619DD9DE700B621A1 /* Debug */, + F07A80F719DD9DE700B621A1 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + F07A80F819DD9DE700B621A1 /* Build configuration list for PBXNativeTarget "matrixConsole" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + F07A80F919DD9DE700B621A1 /* Debug */, + F07A80FA19DD9DE700B621A1 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + F07A80FB19DD9DE700B621A1 /* Build configuration list for PBXNativeTarget "matrixConsoleTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + F07A80FC19DD9DE700B621A1 /* Debug */, + F07A80FD19DD9DE700B621A1 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = F07A80CA19DD9DE700B621A1 /* Project object */; +} diff --git a/matrixConsole/AppDelegate.h b/matrixConsole/AppDelegate.h new file mode 100644 index 000000000..5a7b9c905 --- /dev/null +++ b/matrixConsole/AppDelegate.h @@ -0,0 +1,36 @@ +/* + Copyright 2014 OpenMarket 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 + +#import "MasterTabBarController.h" +#import "CustomAlert.h" + +@interface AppDelegate : UIResponder + +@property (strong, nonatomic) UIWindow *window; +@property (strong, nonatomic) MasterTabBarController *masterTabBarController; + +@property (strong, nonatomic) CustomAlert *errorNotification; + ++ (AppDelegate*)theDelegate; + +- (void)logout; + +- (CustomAlert*)showErrorAsAlert:(NSError*)error; + +@end + diff --git a/matrixConsole/AppDelegate.m b/matrixConsole/AppDelegate.m new file mode 100644 index 000000000..8e570a559 --- /dev/null +++ b/matrixConsole/AppDelegate.m @@ -0,0 +1,133 @@ +/* + Copyright 2014 OpenMarket 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 "AppDelegate.h" +#import "AppSettings.h" +#import "RoomViewController.h" +#import "MatrixHandler.h" +#import "MediaManager.h" + +@interface AppDelegate () + +@end + +@implementation AppDelegate + +#pragma mark - + ++ (AppDelegate*)theDelegate { + return (AppDelegate*)[[UIApplication sharedApplication] delegate]; +} +#pragma mark - + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + // Override point for customization after application launch. + if ([self.window.rootViewController isKindOfClass:[MasterTabBarController class]]) + { + self.masterTabBarController = (MasterTabBarController*)self.window.rootViewController; + self.masterTabBarController.delegate = self; + + // By default the "Home" tab is focussed + [self.masterTabBarController setSelectedIndex:TABBAR_HOME_INDEX]; + + UIViewController* recents = [self.masterTabBarController.viewControllers objectAtIndex:TABBAR_RECENTS_INDEX]; + if ([recents isKindOfClass:[UISplitViewController class]]) { + UISplitViewController *splitViewController = (UISplitViewController *)recents; + UINavigationController *navigationController = [splitViewController.viewControllers lastObject]; + navigationController.topViewController.navigationItem.leftBarButtonItem = splitViewController.displayModeButtonItem; + splitViewController.delegate = self; + } else { + // Patch missing image in tabBarItem for iOS < 8.0 + recents.tabBarItem.image = [[UIImage imageNamed:@"tab_recents"] imageWithRenderingMode:UIImageRenderingModeAutomatic]; + } + } + return YES; +} + +- (void)applicationWillResignActive:(UIApplication *)application { + // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. + // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. +} + +- (void)applicationDidEnterBackground:(UIApplication *)application { + // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. + // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. + + if (self.errorNotification) { + [self.errorNotification dismiss:NO]; + self.errorNotification = nil; + } +} + +- (void)applicationWillEnterForeground:(UIApplication *)application { + // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. +} + +- (void)applicationDidBecomeActive:(UIApplication *)application { + // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. +} + +- (void)applicationWillTerminate:(UIApplication *)application { + // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. +} + +#pragma mark - + +- (void)logout { + // Clear cache + [MediaManager clearCache]; + // Reset App settings + [[AppSettings sharedSettings] reset]; + // Logout Matrix + [[MatrixHandler sharedHandler] logout]; + [self.masterTabBarController showLoginScreen]; + // By default the "Home" tab is focussed + [self.masterTabBarController setSelectedIndex:TABBAR_HOME_INDEX]; +} + +- (CustomAlert*)showErrorAsAlert:(NSError*)error { + if (self.errorNotification) { + [self.errorNotification dismiss:NO]; + } + + NSString *title = [error.userInfo valueForKey:NSLocalizedFailureReasonErrorKey]; + if (!title) + { + title = @"Error"; + } + NSString *msg = [error.userInfo valueForKey:NSLocalizedDescriptionKey]; + + self.errorNotification = [[CustomAlert alloc] initWithTitle:title message:msg style:CustomAlertStyleAlert]; + self.errorNotification.cancelButtonIndex = [self.errorNotification addActionWithTitle:@"OK" style:CustomAlertActionStyleDefault handler:^(CustomAlert *alert) { + [AppDelegate theDelegate].errorNotification = nil; + }]; + [self.errorNotification showInViewController:[self.masterTabBarController selectedViewController]]; + + return self.errorNotification; +} + +#pragma mark - Split view + +- (BOOL)splitViewController:(UISplitViewController *)splitViewController collapseSecondaryViewController:(UIViewController *)secondaryViewController ontoPrimaryViewController:(UIViewController *)primaryViewController { + if ([secondaryViewController isKindOfClass:[UINavigationController class]] && [[(UINavigationController *)secondaryViewController topViewController] isKindOfClass:[RoomViewController class]] && ([(RoomViewController *)[(UINavigationController *)secondaryViewController topViewController] roomId] == nil)) { + // Return YES to indicate that we have handled the collapse by doing nothing; the secondary controller will be discarded. + return YES; + } else { + return NO; + } +} + +@end diff --git a/matrixConsole/AppSettings.h b/matrixConsole/AppSettings.h new file mode 100644 index 000000000..d79184e96 --- /dev/null +++ b/matrixConsole/AppSettings.h @@ -0,0 +1,29 @@ +/* + Copyright 2014 OpenMarket 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 + +@interface AppSettings : NSObject + +@property (nonatomic) BOOL enableNotifications; +@property (nonatomic) BOOL displayAllEvents; +@property (nonatomic) BOOL hideUnsupportedMessages; +@property (nonatomic) BOOL sortMembersUsingLastSeenTime; + ++ (AppSettings *)sharedSettings; + +- (void)reset; + +@end diff --git a/matrixConsole/AppSettings.m b/matrixConsole/AppSettings.m new file mode 100644 index 000000000..b3a0af719 --- /dev/null +++ b/matrixConsole/AppSettings.m @@ -0,0 +1,89 @@ +/* + Copyright 2014 OpenMarket 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 "AppSettings.h" +#import "MatrixHandler.h" + +static AppSettings *sharedSettings = nil; + +@implementation AppSettings + ++ (AppSettings *)sharedSettings { + @synchronized(self) { + if(sharedSettings == nil) + { + sharedSettings = [[super allocWithZone:NULL] init]; + } + } + return sharedSettings; +} + +#pragma mark - + +-(AppSettings *)init { + if (self = [super init]) { + } + return self; +} + +- (void)dealloc { +} + +- (void)reset { + self.enableNotifications = NO; + self.displayAllEvents = NO; + self.hideUnsupportedMessages = NO; + self.sortMembersUsingLastSeenTime = NO; +} + +#pragma mark - + +- (BOOL)enableNotifications { + return [[NSUserDefaults standardUserDefaults] boolForKey:@"enableNotifications"]; +} + +- (void)setEnableNotifications:(BOOL)notifications { + [[MatrixHandler sharedHandler] enableEventsNotifications:notifications]; + [[NSUserDefaults standardUserDefaults] setBool:notifications forKey:@"enableNotifications"]; +} + +- (BOOL)displayAllEvents { + return [[NSUserDefaults standardUserDefaults] boolForKey:@"displayAllEvents"]; +} + +- (void)setDisplayAllEvents:(BOOL)displayAllEvents { + [[NSUserDefaults standardUserDefaults] setBool:displayAllEvents forKey:@"displayAllEvents"]; + // Flush and restore Matrix data + [[MatrixHandler sharedHandler] forceInitialSync]; +} + +- (BOOL)hideUnsupportedMessages { + return [[NSUserDefaults standardUserDefaults] boolForKey:@"hideUnsupportedMessages"]; +} + +- (void)setHideUnsupportedMessages:(BOOL)hideUnsupportedMessages { + [[NSUserDefaults standardUserDefaults] setBool:hideUnsupportedMessages forKey:@"hideUnsupportedMessages"]; +} + +- (BOOL)sortMembersUsingLastSeenTime { + return [[NSUserDefaults standardUserDefaults] boolForKey:@"sortMembersUsingLastSeenTime"]; +} + +- (void)setSortMembersUsingLastSeenTime:(BOOL)sortMembersUsingLastSeen { + [[NSUserDefaults standardUserDefaults] setBool:sortMembersUsingLastSeen forKey:@"sortMembersUsingLastSeenTime"]; +} + +@end diff --git a/matrixConsole/Assets/close.png b/matrixConsole/Assets/close.png new file mode 100644 index 0000000000000000000000000000000000000000..fbcdb51e6bc2f0ba3e0ac1173bdd27c97e9ace0c GIT binary patch literal 397 zcmV;80doF{P)Z#++T;g>`vIx7^1$Oro&Vs~B8Q!gMMAL12Z%~Qa{Km@TbSM1o#DN= zBP@`jE!uSM#>ziTA@WpTw$;7bIH0@(F8qF9V5(b08%(m@M(#Z3~wl}(X zo(Cqv_k9S00LO8l>pHS5TU{=foGLoh=XgA#*Xv>xWp9B+o@rV7J@xYGkCgWm&GPs#;S# rH->kLpswpz#;r%-aUA~#{wu%$^KWmXrIs4G00000NkvXXu0mjfN&~ec literal 0 HcmV?d00001 diff --git a/matrixConsole/Assets/default-profile.png b/matrixConsole/Assets/default-profile.png new file mode 100644 index 0000000000000000000000000000000000000000..6f81a3c417c21f1d9bb4434434c3470f595c8f90 GIT binary patch literal 1722 zcmV;r21WUaP)005u}0ssI21g-FT0000PbVXQnQ*UN; zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU&TuDShRCwC#oj+?LK^Vr(-a-N?u2TrO zokBp1z@~CLtu{qqOS^mv|pf0O;HmzNjT!6<0Oa8v)}Mx!wrjhICni1zdIgCMxOyHm>eSEtj_OV{(f ztE;QCv$L$%(8a~Y`}_Oj<0CCNzcz*M`>CW+TPAMpc3WyK$*6VZTq-SC3|Hu$oSftz z4kQ*lKR+**O9IYnio4zJ`T2Qa9?!Prf0toQr&GG<^cxpKH^mYtvBZuml}f+g$Iraf zybqQ+y}7wTp!;>T$*%;Q4qXYlm>vb3u|>LjX4l}1Ez;eevDD%?u|pH!xY*T_{Sola z6;TibiZc9myG_75Na(`)y>I2Z?yeg}4i~Uk1AYbauK)uIB4Dutv4)aDNm%hbkAQzR z-;!F%(u9gE7N8Mmbk1L^rpwDq0^a1GOUeZmUl1)=J76(loMj3JxLU22D1!m#{~Diw zbCv20i-4)a25dlvMZg417flf`MZgpR6EH=<6aiBNOc5|ez!U)!Fh#%=0aFA_5imu- z6af=3m9}1AUkUgdslK@Ps}_p|0e=rTiXsC56ZogFz*o>XCuIqvv z(Xi0wMfK_LPsR6VA)EvU0_^*~8FW7xBis^%0@(9BoVb;i9LFi#QKJB^)oMl-#D$-R zMFDK;sieZ63kC3OHZu}%;jJ42Cg5Cz)7v9pTJW|)xbPpS4mOYR)6)|Ho9v|#UXIa% z4PUafU;@t3p&9eSAIB$IoDs911q<+eKBs@C1=E7n0yZfO6R^ofJe^KKzPFN_?lMsr zh9D!cxc0MfLO6a1@nnPctH-fJu)5d7m;;7B;jgPNjhXpdv}o8&@J#O(_+N1(FFY(B`xg^*xo8SV6k8oxikSM7k*zFIg}^>EU6aw z769b;n+gC6UE~>*;f+Qk0^Un9gRn+C7z~gdj1IsugP1k3R7c?ZPt@Eti#d-E4-eq; zrUtOs3R=B{w*5*sV8B{a#pXawfYFYosc55W0u1G%wYtcE|4p~2{Q#XDi2X2-xHarHeKkFfBM`b8%f4YDiKk;a^m5X`veg0buFr zc^>%G{pxf&;6rRSo7dOZr>CcYW0O&dqm}}Fxm?nM6UI5;_mSI1GD7h#u<;ljFk0MI zH%@fGT3Wue;Dl1qEs7T+W_KDLu!?3vECM!U%5(`Du!>d@xU+!mf`^qtVb+^=>I)ETjwEC10ckOOzF~VzmZ$ ztYU)}k1c+?kPBss0UQTfrI}Q+=p$;k+p*uy^9+ui|DzfZXcK#^)>^_iw?xd&?b*a$ z<=OcDAZNdwIbb0wCM(Z#Al`Uazb%ViFlToONrr&M4+~l&bK}(0k=So%k#DCD_z-gA zO#QZCPVs1Ynt4%dWXXm$5?337Otv*vb6-D`Nsi{2An@lFd;c%a_%HDGvu{Wm4 zW>k9YpKsfVJ&BmC(pLhi^X*;xB=)XrisdXqzP){)#NPhXS{T2hugqlm)95|Hg1@D&wP%j}K0S!TKY>0L|2>c!UL> QfB*mh07*qoM6N<$f+o^25C8xG literal 0 HcmV?d00001 diff --git a/matrixConsole/Assets/gradient.png b/matrixConsole/Assets/gradient.png new file mode 100644 index 0000000000000000000000000000000000000000..8ac9e2193f43333f923c150b7ff444118e46e164 GIT binary patch literal 194 zcmeAS@N?(olHy`uVBq!ia0vp^0YEIl!3HFArK;8dDajJoh?3y^w370~qErUQl>DSr z1<%~X^wgl##FWaylc_d9MJb*xjv*Dd-rVr!I-tPA>cG14@16g9R@yq9b!w@cz|EuI zy~NFB;?FCFyoYP-_AoOaSlS@#%=h64gTRAx4d!h!4_Y0WO$*Wwus4ftJ0!KDaZ#h6 qWdp-g`vvV;LKnQ{AMD!0#KZ9WB#ZDq6&)#{eGHzielF{r5}E+%9YYHM literal 0 HcmV?d00001 diff --git a/matrixConsole/Assets/logo.png b/matrixConsole/Assets/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..411206dcdc23bad04c623722a35b5398221863e7 GIT binary patch literal 910 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 literal 0 HcmV?d00001 diff --git a/matrixConsole/Assets/matrixConsole.jpg b/matrixConsole/Assets/matrixConsole.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3d17aa9f856273d47cc439536512d6fef54bb9e3 GIT binary patch literal 22884 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 h;ElZu3|sFqFl?NQDz4M;I1ZP7zpG4&^>1 zAW#m41~CF6snlwVG{_;Ppdl$qK`KIsjW)F*r5eNYdH8nNX2M!!4 z5FA;1d;7}x`1rWGy1H%9k}&N6M1Fq0x1XP1&ZbS9__Qqp1A~sVw6sr|%EjnqbfBuL zI!rqyBmXcrH}~+&%#6%xrUjSFHHnIfN|cwEpP+3A1_ovg4GpP@9mv_UXTPMKsHv$9 zUA%ZPLfFw4wv?BbJGr{L77J*)su>LPD<5#@nZUN<0dadGjq zKVxI#R$;)b*zlP%XTGA1dV724kBp3{2rCp>;8IuzD5x_5bmhvGFaaXpw`#U}+exSFdrNu-PAs{>q1B$3XP=bPj zG9U}_Q!@`9Ja7^kNKQ_UA036v%*;Sh1rQeytV^sD$m8PT^5;_PZP7=Vhc-4gHTcNg z-Tf}pMY<#^fsoMK2;nwfPESt{mNX!vqoW(Q zY}wKU`A(cTabEC0X~6&zxy1PRxB@YkBm4I4E0nY>P)SK?)XU53rCem%y9@sJFCZl) zC9b$5=@BWEUWd!m)ALu{Nh)B`(a~YBB#`RrY8%{l?%Y`_sku3c^(y4#_UI?jRo_wA*+vffK{j-H4 zANKFx{}VnS0a_=5Nl5?#Du^;Eh|+}uQeIx}$YQbJiRZ(^!;{}M2nbFI?$FTCYm5jw z0HCbJ&6_uU-V_K#4|aBTRg`1v?(WuM1O!}?wY7CE8o>TVMMZ_fdV_$!ICA7jCLPe+ z++07AxL+_8%F4>mnXuyG1VO@}bPD3+$&=r$ij6NSD)Jzy+Z~lvR;N|7@ zGxih31>nVt7aJ225@P9qp~S?*BnV5{GU^Nom#3%aFSH}#VJD6qJC?EZ;102`uWugmp>^A5M^2EEk`e|`B$(5Cow9+ILjq=IX4Z^neSLkJI33a6 z-fl?ZBm=?h63%z;-n~W9(b4BUJUo6|_mdAO0|Nu2Q zQ{U9q)>^Gr4zV7pA!&dH4h`UB1M(T9rP%EPpe>hSFUV@_`? ckbeXi02X8x{*mSVJ^%m!07*qoM6N<$f|8hQ_y7O^ literal 0 HcmV?d00001 diff --git a/matrixConsole/Assets/tab_recents@2x.png b/matrixConsole/Assets/tab_recents@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..005b2265e4d5f2fca0d1c9713306939b9018f542 GIT binary patch literal 1890 zcmV-o2c7tdP)4M;I1ZP7zpG4&^>1 zAW#m41~CF6snlwVG{_;Ppdl$qK`KIsjW)F*r5eNYdH8nNX2M!!4 z5FA;1d;7}x`1rWGy1H%9k}&N6M1Fq0x1XP1&ZbS9__Qqp1A~sVw6sr|%EjnqbfBuL zI!rqyBmXcrH}~+&%#6%xrUjSFHHnIfN|cwEpP+3A1_ovg4GpP@9mv_UXTPMKsHv$9 zUA%ZPLfFw4wv?BbJGr{L77J*)su>LPD<5#@nZUN<0dadGjq zKVxI#R$;)b*zlP%XTGA1dV724kBp3{2rCp>;8IuzD5x_5bmhvGFaaXpw`#U}+exSFdrNu-PAs{>q1B$3XP=bPj zG9U}_Q!@`9Ja7^kNKQ_UA036v%*;Sh1rQeytV^sD$m8PT^5;_PZP7=Vhc-4gHTcNg z-Tf}pMY<#^fsoMK2;nwfPESt{mNX!vqoW(Q zY}wKU`A(cTabEC0X~6&zxy1PRxB@YkBm4I4E0nY>P)SK?)XU53rCem%y9@sJFCZl) zC9b$5=@BWEUWd!m)ALu{Nh)B`(a~YBB#`RrY8%{l?%Y`_sku3c^(y4#_UI?jRo_wA*+vffK{j-H4 zANKFx{}VnS0a_=5Nl5?#Du^;Eh|+}uQeIx}$YQbJiRZ(^!;{}M2nbFI?$FTCYm5jw z0HCbJ&6_uU-V_K#4|aBTRg`1v?(WuM1O!}?wY7CE8o>TVMMZ_fdV_$!ICA7jCLPe+ z++07AxL+_8%F4>mnXuyG1VO@}bPD3+$&=r$ij6NSD)Jzy+Z~lvR;N|7@ zGxih31>nVt7aJ225@P9qp~S?*BnV5{GU^Nom#3%aFSH}#VJD6qJC?EZ;102`uWugmp>^A5M^2EEk`e|`B$(5Cow9+ILjq=IX4Z^neSLkJI33a6 z-fl?ZBm=?h63%z;-n~W9(b4BUJUo6|_mdAO0|Nu2Q zQ{U9q)>^Gr4zV7pA!&dH4h`UB1M(T9rP%EPpe>hSFUV@_`? ckbeXi02X8x{*mSVJ^%m!07*qoM6N<$f|8hQ_y7O^ literal 0 HcmV?d00001 diff --git a/matrixConsole/Base.lproj/LaunchScreen.xib b/matrixConsole/Base.lproj/LaunchScreen.xib new file mode 100644 index 000000000..fc64e2f3b --- /dev/null +++ b/matrixConsole/Base.lproj/LaunchScreen.xib @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/matrixConsole/Base.lproj/Main.storyboard b/matrixConsole/Base.lproj/Main.storyboard new file mode 100644 index 000000000..482cbb7d8 --- /dev/null +++ b/matrixConsole/Base.lproj/Main.storyboard @@ -0,0 +1,1064 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/matrixConsole/CustomAlert.h b/matrixConsole/CustomAlert.h new file mode 100644 index 000000000..79080c397 --- /dev/null +++ b/matrixConsole/CustomAlert.h @@ -0,0 +1,53 @@ +/* + Copyright 2014 OpenMarket 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 + +// Note: UIAlertView is deprecated in iOS 8. To create and manage alerts in iOS 8 and later, instead use UIAlertController +// with a preferredStyle of UIAlertControllerStyleAlert. + +typedef enum : NSUInteger { + CustomAlertActionStyleDefault = 0, + CustomAlertActionStyleCancel, + CustomAlertActionStyleDestructive +} CustomAlertActionStyle; + +typedef enum : NSUInteger { + CustomAlertStyleActionSheet = 0, + CustomAlertStyleAlert +} CustomAlertStyle; + +@interface CustomAlert : NSObject { +} + +typedef void (^blockCustomAlert_onClick)(CustomAlert *alert); +typedef void (^blockCustomAlert_textFieldHandler)(UITextField *textField); + +@property(nonatomic) NSInteger cancelButtonIndex; // required to dismiss cusmtomAlert on iOS < 8 (default is -1). +@property(nonatomic, weak) UIView *sourceView; + +- (id)initWithTitle:(NSString *)title message:(NSString *)message style:(CustomAlertStyle)style; +// adds a button with the title. returns the index (0 based) of where it was added. +- (NSInteger)addActionWithTitle:(NSString *)title style:(CustomAlertActionStyle)style handler:(blockCustomAlert_onClick)handler; +// Adds a text field to an alert (Note: You can add a text field only if the style property is set to CustomAlertStyleAlert). +- (void)addTextFieldWithConfigurationHandler:(blockCustomAlert_textFieldHandler)configurationHandler; + +- (void)showInViewController:(UIViewController*)viewController; + +- (void)dismiss:(BOOL)animated; +- (UITextField *)textFieldAtIndex:(NSInteger)textFieldIndex; + +@end diff --git a/matrixConsole/CustomAlert.m b/matrixConsole/CustomAlert.m new file mode 100644 index 000000000..fc01ff877 --- /dev/null +++ b/matrixConsole/CustomAlert.m @@ -0,0 +1,210 @@ +/* + Copyright 2014 OpenMarket 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 "CustomAlert.h" + +#import + +@interface CustomAlert() +{ + UIViewController* parentViewController; + NSMutableArray *actions; // use only for iOS < 8 +} + +@property(nonatomic, strong) id alert; // alert is kind of UIAlertController for IOS 8 and later, in other cases it's kind of UIAlertView or UIActionSheet. +@end + +@implementation CustomAlert + +- (void)dealloc { + // iOS < 8 + if ([_alert isKindOfClass:[UIActionSheet class]] || [_alert isKindOfClass:[UIAlertView class]]) { + // Dismiss here AlertView or ActionSheet (if any) because its delegate is released + [self dismiss:NO]; + } + + _alert = nil; + parentViewController = nil; + actions = nil; +} + +- (id)initWithTitle:(NSString *)title message:(NSString *)message style:(CustomAlertStyle)style { + if (self = [super init]) { + // Check iOS version + if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8) { + _alert = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:(UIAlertControllerStyle)style]; + } else { + // Use legacy objects + if (style == CustomAlertStyleActionSheet) { + _alert = [[UIActionSheet alloc] initWithTitle:title delegate:self cancelButtonTitle:nil destructiveButtonTitle:nil otherButtonTitles:nil]; + } else { + _alert = [[UIAlertView alloc] initWithTitle:title message:message delegate:self cancelButtonTitle:nil otherButtonTitles:nil]; + } + + self.cancelButtonIndex = -1; + } + } + return self; +} + + +- (NSInteger)addActionWithTitle:(NSString *)title style:(CustomAlertActionStyle)style handler:(blockCustomAlert_onClick)handler { + NSInteger index = 0; + if ([_alert isKindOfClass:[UIAlertController class]]) { + index = [(UIAlertController *)_alert actions].count; + UIAlertAction* action = [UIAlertAction actionWithTitle:title + style:(UIAlertActionStyle)style + handler:^(UIAlertAction * action) { + if (handler) { + handler(self); + } + }]; + + [(UIAlertController *)_alert addAction:action]; + } else if ([_alert isKindOfClass:[UIActionSheet class]]) { + if (actions == nil) { + actions = [NSMutableArray array]; + } + index = [(UIActionSheet *)_alert addButtonWithTitle:title]; + if (handler) { + [actions addObject:handler]; + } else { + [actions addObject:[NSNull null]]; + } + } else if ([_alert isKindOfClass:[UIAlertView class]]) { + if (actions == nil) { + actions = [NSMutableArray array]; + } + index = [(UIAlertView *)_alert addButtonWithTitle:title]; + if (handler) { + [actions addObject:handler]; + } else { + [actions addObject:[NSNull null]]; + } + } + return index; +} + +- (void)addTextFieldWithConfigurationHandler:(blockCustomAlert_textFieldHandler)configurationHandler { + if ([_alert isKindOfClass:[UIAlertController class]]) { + [(UIAlertController *)_alert addTextFieldWithConfigurationHandler:configurationHandler]; + } else if ([_alert isKindOfClass:[UIAlertView class]]) { + UIAlertView *alertView = (UIAlertView *)_alert; + // Check the current style + if (alertView.alertViewStyle == UIAlertViewStyleDefault) { + // Add the first text fields + alertView.alertViewStyle = UIAlertViewStylePlainTextInput; + + if (configurationHandler) { + // Store the callback + UITextField *textField = [alertView textFieldAtIndex:0]; + objc_setAssociatedObject(textField, "configurationHandler", [configurationHandler copy], OBJC_ASSOCIATION_RETAIN_NONATOMIC); + } + } else if (alertView.alertViewStyle != UIAlertViewStyleLoginAndPasswordInput) { + // Add a second text field + alertView.alertViewStyle = UIAlertViewStyleLoginAndPasswordInput; + + if (configurationHandler) { + // Store the callback + UITextField *textField = [alertView textFieldAtIndex:1]; + objc_setAssociatedObject(textField, "configurationHandler", [configurationHandler copy], OBJC_ASSOCIATION_RETAIN_NONATOMIC); + } + } + // CAUTION 1: only 2 text fields are supported fro iOS < 8 + // CAUTION 2: alert style "UIAlertViewStyleSecureTextInput" is not supported, use the configurationHandler to handle secure text field + } +} + +- (void)showInViewController:(UIViewController*)viewController { + if ([_alert isKindOfClass:[UIAlertController class]]) { + if (viewController) { + parentViewController = viewController; + if (self.sourceView) { + [_alert popoverPresentationController].sourceView = self.sourceView; + [_alert popoverPresentationController].sourceRect = self.sourceView.bounds; + } + [viewController presentViewController:(UIAlertController *)_alert animated:YES completion:nil]; + } + } else if ([_alert isKindOfClass:[UIActionSheet class]]) { + [(UIActionSheet *)_alert showInView:[[UIApplication sharedApplication] keyWindow]]; + } else if ([_alert isKindOfClass:[UIAlertView class]]) { + UIAlertView *alertView = (UIAlertView *)_alert; + if (alertView.alertViewStyle != UIAlertViewStyleDefault) { + // Call here textField handlers + UITextField *textField = [alertView textFieldAtIndex:0]; + blockCustomAlert_textFieldHandler configurationHandler = objc_getAssociatedObject(textField, "configurationHandler"); + if (configurationHandler) { + configurationHandler (textField); + } + if (alertView.alertViewStyle == UIAlertViewStyleLoginAndPasswordInput) { + textField = [alertView textFieldAtIndex:1]; + blockCustomAlert_textFieldHandler configurationHandler = objc_getAssociatedObject(textField, "configurationHandler"); + if (configurationHandler) { + configurationHandler (textField); + } + } + } + [alertView show]; + } +} + +- (void)dismiss:(BOOL)animated { + if ([_alert isKindOfClass:[UIAlertController class]]) { + [parentViewController dismissViewControllerAnimated:animated completion:nil]; + } else if ([_alert isKindOfClass:[UIActionSheet class]]) { + [((UIActionSheet *)_alert) dismissWithClickedButtonIndex:self.cancelButtonIndex animated:animated]; + } else if ([_alert isKindOfClass:[UIAlertView class]]) { + [((UIAlertView *)_alert) dismissWithClickedButtonIndex:self.cancelButtonIndex animated:animated]; + } + _alert = nil; +} + +- (UITextField *)textFieldAtIndex:(NSInteger)textFieldIndex{ + if ([_alert isKindOfClass:[UIAlertController class]]) { + return [((UIAlertController*)_alert).textFields objectAtIndex:textFieldIndex]; + } else if ([_alert isKindOfClass:[UIAlertView class]]) { + return [((UIAlertView*)_alert) textFieldAtIndex:textFieldIndex]; + } + return nil; +} + +#pragma mark - UIAlertViewDelegate (iOS < 8) + +- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { + // Retrieve the callback + blockCustomAlert_onClick block = [actions objectAtIndex:buttonIndex]; + if ([block isEqual:[NSNull null]] == NO) { + // And call it + block(self); + } + // Release alert reference + _alert = nil; +} + +#pragma mark - UIActionSheetDelegate (iOS < 8) + +- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex { + // Retrieve the callback + blockCustomAlert_onClick block = [actions objectAtIndex:buttonIndex]; + if ([block isEqual:[NSNull null]] == NO) { + // And call it + block(self); + } + // Release _alert reference + _alert = nil; +} + +@end diff --git a/matrixConsole/Images.xcassets/AppIcon.appiconset/Contents.json b/matrixConsole/Images.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 000000000..65501812a --- /dev/null +++ b/matrixConsole/Images.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,122 @@ +{ + "images" : [ + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-29.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-40@3x.png", + "scale" : "3x" + }, + { + "size" : "57x57", + "idiom" : "iphone", + "filename" : "Icon-57.png", + "scale" : "1x" + }, + { + "size" : "57x57", + "idiom" : "iphone", + "filename" : "Icon-57@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-60@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-29-1.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-29@2x-1.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-40.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-40@2x-1.png", + "scale" : "2x" + }, + { + "size" : "50x50", + "idiom" : "ipad", + "filename" : "Icon-50.png", + "scale" : "1x" + }, + { + "size" : "50x50", + "idiom" : "ipad", + "filename" : "Icon-50@2x.png", + "scale" : "2x" + }, + { + "size" : "72x72", + "idiom" : "ipad", + "filename" : "Icon-72.png", + "scale" : "1x" + }, + { + "size" : "72x72", + "idiom" : "ipad", + "filename" : "Icon-72@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-76.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-76@2x.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/matrixConsole/Images.xcassets/AppIcon.appiconset/Icon-29-1.png b/matrixConsole/Images.xcassets/AppIcon.appiconset/Icon-29-1.png new file mode 100644 index 0000000000000000000000000000000000000000..31fcb2c662d446e6c227986dcecec17abad5a972 GIT binary patch literal 4015 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 literal 0 HcmV?d00001 diff --git a/matrixConsole/Images.xcassets/AppIcon.appiconset/Icon-29.png b/matrixConsole/Images.xcassets/AppIcon.appiconset/Icon-29.png new file mode 100644 index 0000000000000000000000000000000000000000..31fcb2c662d446e6c227986dcecec17abad5a972 GIT binary patch literal 4015 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 literal 0 HcmV?d00001 diff --git a/matrixConsole/Images.xcassets/AppIcon.appiconset/Icon-29@2x-1.png b/matrixConsole/Images.xcassets/AppIcon.appiconset/Icon-29@2x-1.png new file mode 100644 index 0000000000000000000000000000000000000000..969a78955ba363f4ee1de70d9cda0f5f942c159a GIT binary patch literal 5233 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 literal 0 HcmV?d00001 diff --git a/matrixConsole/Images.xcassets/AppIcon.appiconset/Icon-29@2x.png b/matrixConsole/Images.xcassets/AppIcon.appiconset/Icon-29@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..969a78955ba363f4ee1de70d9cda0f5f942c159a GIT binary patch literal 5233 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 literal 0 HcmV?d00001 diff --git a/matrixConsole/Images.xcassets/AppIcon.appiconset/Icon-29@3x.png b/matrixConsole/Images.xcassets/AppIcon.appiconset/Icon-29@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..68bce94d387727f0f645c3863d1e94842755e28e GIT binary patch literal 6495 zcma)g1ymf(*6rY~!685(cyNcoJ-7!#aJL}?0|N~1E+J@;5C~52KycUK!9BP;4EmGr zepmjx-h1oSTGd^BdY`?kPMxY%-4PmU3OJY)m;e9(M@dmu>*=olr=p`iUElZ3IsyQg zvUV~u8cH%Uv>ITLwVk6C0HBDIne3rMG)>yOJmkn(^DddrYNz=-N*+hE;zvfz!9zr4 zgDET03PD*Ey2x;Jy_d}9ZMMvWY`JgH(Mk3ZFz8-m%M%cP9O|LExDsW8->WUrc!;0* zTxEG|E!_^21DFwBAe!Np0wn7+=wi>Wtb4kdxK5e@sIvY@0sxo#hTKu+R$KpaNfQBH zQb^*72^QkY1-ri?p!_XzFmIaQ&f}3x0vn++z`tV*AWAKf5(R!SU;rmfP|21}%SvRi zAfvb7PNy9x=25%t+Vs1DnX8kZRfPa26_TsNQ+|GUPdY$(mIq5pz)y-gMZSY2fpSW- z8Ge%F+@V@|31ol30))~{Fun;*z6oA1|8c-BU;q@uGp=Tc@k4b|8Ir7Sf9Z(D3xL=kM?;`#3`a;86s z1J}L!^+>(u_xxJd&}74mx?g=G3NC$KNai+x+`(6~D4iuq*GIsE z($Tti+=_k6ibn36?m%PYeyuEM{~d?tiC*QVrxYlN)d&hPSU0ZGP` z2#EAyg+Dcb79CIX1w|gJoeXL`xg}O5tw$dzW&qu1C^Px%px}5SL)@~U*E!%qia9)f z$z>U)9M@5+LYf~)I5NLSk48nw0$8}7PX*(cv8AGTx3|0SHQ}oTk#;JtN<(>#P^LQ+ zR`jl^V8ksLcpLI=f%>ly)VV7juVkm8EhFL58@j3C{?WyX{SXR&dNnI#LPXWW=#| z=$Y?Tvd>`6WXx#pJ5b^Fwvn%XazUtv8lgIqmlJ)boQ@Wa+Ut#3`Fad(qFBN{3dQSm zJtl+^_%c19KVbU;BqIG}XrI+!)FDeqBT6a0Q7(K*#rTO48@~sgR~97~VJw79ew`o% ze=r=m_-@g5p>n_Be$WaZ!X@fLr!?q6*_)VrD;qC4wh^LnJH-76DZ8 zRo2W+)tX6?jZCUa1IL4t!C|L~uk$Ii#ELLZv(zmXnmGn4erS4NTO36ljm09ep{(? zQn6;$&GZ_|Aj4q7kfrr`93lVgH9cSOR|SiS`Wi@$$Q;TX^K%8kT(oiCZHDus?dEeO zD+Vj?4YCcy4T=rz0U7LIvp#f7OYQ-(Ub63GM>>4EO*+@C89M1Ys5)PDw+g+APj#bo zGju`4E!q~v@M5cCCtU|^@0?goLESiw5&h*azEVEsxIVFaREM9|gnKs^e);pO@YC@p z+fj{fkEM=Jj-O8x*&R*-zX^Zt9zC5L7%d(ZDdR6!op7HfvDLTD9`ha0vG(GwPSqXa z*vyL!Rr8P4v1wKNHXL1^a0pwh{qge$-npXJt7e^M%x1M_B_F4Ijr)z8m>UnAaMV{p zZb8pc7f~ld?fHIyRQNBsj2(>}V4cV|9X$PfvrgcjL;?^l zRlzdu1KyyYR6mie8-L#XtlS*lls+>&lfsG&Ns-Hv`_f&((8<#UF0;zmaAor;K`trN zThyZ|dtO>yx>tHM%RGxbTUxtQ0biV&Om=u{;oTW)zh(1%pnUN#q&ZD&**EUq2`ycw zuoE>*EetPKE!Mo3vG+ZbPl08@JGG!!B5a>@2Y#$aLoVHoH(=xNvZyanT^p%`pmLJ( zwDPcb*+cy4gV}EdJ-Sq!_C zRj+xyc1%O>La<7}PY_4%M39D5nd5!E8N3~h1qwTXtQn5)PPxs|Fr zdhTm{(p`wGFFDyg3B0~UhDobP`*chqE~CtoMl*`MBw<)Gw5_QyUEPq|jjAHae4VJi z_VT%U4`VMQjhgQW#_vh+S1m+s_k0!b?85T}8=$%|3h2{O59d}~{*V0R0&yi*<@scR ztiuH3H1QXvSj8xuJcvA()+#okR@6hEen$SZA7->|y5I7##bca-kTLzn9zWR1Z=Tb~+OkhlN#=gM8!g*z?J}kfMM_$#s56k!S0YQOf z9UtCCVTdaz&0;o-y`H^;{d=94qnJ+lo0b}w<=gGLDNJj*_uVB2O7oohbNYviQgbgB zxpj!Oezj=(Z6#+Ol}wa?rl8Y&N8>ZKcGKt1ONRksS>EZF_J{1Vx6aw7%Ln%lw{IPA z9N6$yaMzzhjYzep@7ed}L%l9;5^wO(LeRo+<*0YazO5fL)5;!Lb#L_4M!3Uz* zM{^mk(k}&h)0JZbzl?uTZ&iPIn5tZ{$m})f&G6;AHq*x{%daQ4e>W~No4h12Nxi(} zN4G6&6Xu{W7?&(T4J>l4+Dtkvs+!1~2q~}`c_qdR(Q|WOGn#8i7|t8^-ugYfydAl{ z+l&ue9hYm3+G=e6F=7O6bUUpY+<2z{Mt`nc#MtTJ{k9#vf3+alxOZtvyrAXMVR%~P zX6rJW`j||}V{z-In=(MKeCd-%_2bmt+wW-4(88S0oFy7QK(@LUn;Lnq^p<;C>?i!$r}+6#&3` z_NO8M(m#;_0EmKiI&a+GsH%uqfSfqYEJ5a098f2hCo}*6go->hovhrgnue24#14rT+)XKY3)WTrI$M zE^c-pXWBo!X67J>n;0G4AEAGhfArJM&ida<&aQtC>uG?Tf8KC%b8vC~i~GqH_{S>p zM$5_-BeZ|Lq_Ha&iG%xw`&Q;Qm|SKW+bwR|nf! zJ;ma$9{m&lpSJ(TYuJL^Ku_}mwzE)jcC!LMiT&;U&*A*v5r1<5Isb(AKSKSFdHl=z zG?C(%K+b<9g*axoIUEN7!1h&=mC}JC92n|{lME7aOr%ewYjBqmXliP5e=+Y0M<9?x zeiliawf8|h9B)mRJBnOZLjyY%zuB70G&a?BSh&0hf|v0RBH{deEJR zX&0{*sP1h(InGuQ_{Q?!qerOXhImG6!sEm&x9 zeKZj&$I+--dC5j|-m$Z@bAG;~J&+|PO3bX`k4f@sn~ehfaIHHkLWnSl)gW^2J4l^D zIXQ_dK^OJL@L3>S{pRrw&g%m|mGkOP<7L_y_{b(3Cn3vKvHkd~M8C#ngxc$TJ3%Lw zoOd%U{=N$bW;c+;vf2NEsRhy+)o+rp$~n;FdvEA#(&~$26*+LQ&@fTsG(Y9GJ=$Js z+-x`}ZKH!I-o_G+C`L*jm4Nz!Z{-;}UDge{Uykg^TC5MeL#4j()l41rv8M0igIEl; zSh`xaxN83EkGWQZ$x40WH^>lU&5Jc{YyXhAZ``ab)NN=&D4M1*6v3epoc68QSt!>> z{m3GEp5G3=j|>YgOl9OZ0|{_MhUy;>H23nxk$xI@WwzekK*lQBNzKafqM4KmZ`G0DaYEc_i0?Q z(P8*E>NQfV(#FyOCGu^3su==fXImphwqv=IwGR4l+39a4>Uh+^c=eihjqa0`77Bs- zPV;p!?)x)RoF*+vBdNci*E%m6wjpf;kRZ302hYR=K}#>O2^mM8WHkqq*)gb5XW8G@ zDbjcxE+puC-(7Q;8P>jbdyh@*EfhNttov1ke0QONH&f_+;8VX8NI8x3KGp}f{Z_@dCB zD`@<0glFQ6s;J8)LCIyTsZ0_g~1x z&Fhn9>48Cv>RGQKU*uy5jen-|Z}{F`I_}n4-#SYWOCaJYCf})s4Pt<-g9gm@a=u?YA?Y zzvP`Q>?(h4FWL*KhQYz=Q^V*04&R(ol&eMWiL$qX-?Zl?af!eB-rpE!9(-;hGu@jd266kR(lT2Y50!~0UrJ%DSaTr7AXT|HMgy;VRvVTTSgsoU<-kq1# z86oU-Ubww6N)OHu1YNpu7*xqZcSEk{MzdrRiwtXvS>FAqNum^Rv^8#mo_yG!29dL@ zEC*1sZh{NQyAYOR`JYmOP<)Ne+$D;Hef#?4cZUVu2hqgKJNTJ0OvVw_>>_NY)@4;1 z#Ave@fsm3qn1k<~reYl4k6l+I!+Lq((8CL*5r^eShhQpY&UI(0QPG8W67t)QO75QL zdet~CKP4pF3GvQiZyZgx^(5z;3dw!Rx0zg?>D3vi;!J29C1WZ6@;^^TSwzqzU#C(@ zvVN;tnFXh+sAU0_wuUpm$b{h%`0Ku&e8G8j-<+dwGBxFSe*;+?m87bZ#X+SGc2jX8 z=()mz#!CtCIxh$z))TYoy~HKvk-X!NY<4$sza7d7(nn3JJuN!pr839NJK#_E05^S= zkD(YlUhT9yTxd82`aQtsG;N+)g=;H#0~2zzl&KY!KmN2J!mA1Aen8kx7G9_#K;LA}>5s24&Ih6SbCf!K z#-w&Wp0n8KG1$?j_C06hLAOw&oh@6;ThDC;vC&Z&NWW1cbJa9js_>1w+5fe^2gw+R`Ub5*?PX)mfO?W*?r z>V-d^+po>2%&J=oqVlQ$=TSo%)b)y4kNBLn)X%gQnhtisLpLoEq(ef@(B# zY&qOh*h7oSbB5FOO*6a^?T;G@8U%T5A`{JNHdxdk?T9Q;WXqkbOyC)%;BP8SU8ay}x`&1&-Qq6hkr-FNWfd5%3^OX4?g zhtUwAj_?vitg;kh_|2+Mid3!W{hPwDIKyvOmIs5Za1+e(z@RkW?nvS)O+>K=nP|UL7>aaU?8!mr8hhk^<1>+DkUf?1P!Q((Ju@nysZ+t4ead* z^5iwT29)_dK2({uds30$%%rxDiI6;d!xK~yKAMDkbCPd5U-|kYtJb$RhzUB6e`XYSg? zxjJxAk9g9FAYmYUg-Cy|{UZqy5-Ns`ujllp_cv_+ zbYn0SP3pS-m?ZzZpT7ke72jGZj*}!1e{-(ZA@p}elINAop~3sHtMDdi3;HIZ5Sxo8 zzcrLmgm(lak zxl0iL1bqv-o*fJq%-lANGVKDjDvX#K^Z}}SNdOc;y1xH(8kBytX^1t9&y@(t#>Nd; zk&a*;A30M;;2QD{ZD+z?;Ce2UHbj6P-H;~eT5E>yvJxuAk{gXANatdfF6`2oL!{Xg zKuJ)~^^>aJOe2!{cUug)QK~iW0vEGf()$&8WDXTxG-t9Tx&a{Inj{CWZniQS-xja2LYcLhLr%aDudC$0Oa39aJzNAR?lGbfgL* zO?sDJ0#fzi*Z%MQ>%Cd)&fM9v_dfTYbJv}j7(E>|S}Jxb002O%j#M$YxbpvQ6u^sf z{Leaf0DwxxSy@?6U0E5dhekO#yV(N(NZOnHB8hPPzJ!VSnL zyi`3~#F}O!_AHfBDrAt@XbR)&{5Bt*_!(~$no>|OZxB&JG-z%!Tz=Bq!Ex|Imhbpn zXPVnjen0p}uHVY^X+Il)pXe&FH3$z-sMUic5`H*zwDXDVHUNMsp(K(3&$@SopZS}d zLMs$3CB;~L9_?CE6VDz9h28~Jn3Fyf%MAJcYg;+x2BRh*v}F(=%XKR~4t=%T?3gh{ zD^Dde_mO}t>or@^EO2)jOy{(1IphRuqsz8m9U(WYmi9V2z3;IXOZS!iVr*&(eQMku z=@~W^m50{161KI~l<~^ncL_)ssU_Id7Bm8&T22V1!^SC8=VAXiJZ*o zLf59CSwH0gi_}C;o2P3*tknVP=|~k}W8>rF<1}LVQ3K=81M4Ah?BQ9^(VCp*ctDb6y4Z~I8UDrOQ#?m$M&^xq&tt8)UtIGcoJU4?EtjmhKItyS9V-!DuwuGNTf}Ro zlyVgyT?{a?mZtTcCYn=0ayDF+E0dECHxc3!BR^q~XwQ}Itgtl6)it8j}`S8sI2+E9yz#Ykb6kz1&Di*E}#QKnk{d7`6&#rl7XIW{o6%6dRrL1Sx6|GYrv2k`Erpm+i!N@+fr@HM59E?GlYA6dPN)<_Zc+XU99>lg~t@! zI3#JalZ0A~ZPu%V#;C`#$MiQ`IY6Bs+2)>l64m)z06o|$nBHC)jhBsE?@X9|w&VYS zeVS%FlCITzhY`zwuf2L$iZToA$Ehyr7@T=OdjEp7Vr9_oKFmPL;(`- zVzH^%7&$GRrhZ|D!C0zFY-)8TIvJgYj@o;qQNnJ3D5W%{^bva#7MOdId~!RH*HM6l zzw@yk{!2`_i3mWtxZ9T@-e9qTQ^WtZ!Mj4aJQ<7#;~`8)g{-4WAjU zya+7YGm10HHbRv(-mxt^F0(IlH*&obl%J?CWt5~hU@}vLQw+8N1t+d^Y(1Tq>0F-t z8Y-bB0g*^^=J>oim@zawL>Ogq-WryBB~#G;d2hJ;bJ=HjxkQEb7vE84CljZJIhozO%>$0nUu{qYqkTiB^L^?mhp1Z3dN2Ezub2Au}=VE1#q^QDu7 z6F=H$;LUJMI45ul_$BgoWL4x9nr}3DtflN^>_QSQ;`Jyki9?b5ZWgZCR#L|n*eCIE zcXS_qTURJrJ;Sa=^tAF0FpzLUPH<^E-*{k!{$)Ugris=2B~?Ug*Our_qLefE;~ zjo_E0FUyUmjJeA>@vrgg`0a82anf=8o9~s!QzOG^uI9Eut%)uxj&HjwrnVv)G7&Sl zq;q%jEaexiz$l$4x>(0RA6|-%b zW&8Ojb3SeB@7}(7JNCXkC~LFjezW{~_|efR(<$LZ@VNg+`C;(t^Y!%Q(N(GM+p|r* zzuW+lU}-DYk5>5(V5!Qhp0F+fCsjQY5guv5I{1-(v~#p{@iit8E!7lrU`TGW+}wv+ z5qf6UTA>ZaI{l;h9qwzM408+;3`y7AA?a$qYJ-K33PEZOiHC{8ag9a(8X_!OYStxq6@W#rC=M^V;z_=FtmMibdR$xhq2^ za}E*HPjPap>Y3k+<7;o8Ke6EVv-WuZF!86>0WzUvy`(i@D?lOuwP(AR#KM2Ebp@tn z2#?p;xs}cgq0+6>ywZJyN6i`?j(4bDT|PBYx^c(Yw_?cLsLloR=GU6CE7BDnud z1>O?6r6gwzgT>y<_;{l-ZO3zk>V#T^-qr@XAq*=_8*8w3=Bu?MR1T_M?Jqagzd=nV zOtz*JC$3J38eTT|+IS~qB`s(B<(HSJ5&u!~?V+(Z&Z7j6>8&tCZcx^t%a+jisYjmG z%;x#eQ*&2Z*Bf-RphZr93zj>h=R)h>A_EUj9-YvUN03K>RJqn%JYAfm@m_U!29H$9 zL~eCC^rmdy_C)s0tV1cWEX~9RMMFipO}amSj#SOs=5(5MX5&PTtWBuPOX@DW+#78qg>T`lG1K*$(4FnFQ@L6R(~n}67k$|;3h)M#~9-~Z!z&MrN6j8 zXl0>)W;J$ot$`jpH>BDWxAMNBe!v3#9Gx z^3NL&UHeDjCo6|}Tsy4Nep4$a?N`F2DyEV1y4YA36{7x^& zi@@fb2RhUrB}`;1qs&n6XWARDWPb`t3b8zBUR3VvoK5=S_}bC&7l0&V|BL}NXm#;f zN$H6+^9BH@Fa2&rfUKvi006O+v!N-*R9g#fi*gsXwnN$23;Vl!Ua$cGIe+*?*WDgt z4fc0;^YDiIBOre;;1~VhFcbp*gMx8IKuopuz{)7JJy=3mTv!AmPXz{p<=JVTMUJ54n2lan}{|WS`!0i7L{2TmlfilY76K(J9{X2r_UjhD&{Wo71 z?QDOMi$6y6H~-(*fAjU6P#DxjUC_?9>K+(-^hL10)PGOs|7ZN=B?tYT+JB|`&pQ5r zUKCQEN)GzZqL8PGwmGH+07#S7RTK?PDL0LKphfyjx7^4;}u&L0ex&-f^C(2khW_7D%b=mFZEFR_t zZ3j$w<5qAI0)m6Lw3b7pB|&`@BGXiCY~nCh6mb5ll!%j^$TZFB!LHHyYWe{k4Q@D8 zKD23<_i>EKbdhOeUv)rmu(qbACgJF)>jVmgV$CzJ@_mp_Mr?$)rR|vZe4K7?Cp#v= zRqEHOa5plL*bph2^vq68aV{+{8yFZca%c59G?w?)z1x{LJglT^33PCXTwYnp?7R!? zUs+yW{kAIgkCZ`!9;gI~z9NS}q)8p=NL~3HOh}-G%g7WQ9Qfo$MMm-?5IF;zlCr_Sc5{G0VAuM=5P={bAjjq6eSS|Wfm5eT|VP?4Gl}dJFc#-SRl^V*H~Zd%_gNr?nep+`9K`{L*Hso? zUZN%d>W>SEST^tw%|;jm`pTZ}R@1xyfyqYhB9Z#4s$@QXewUt>vRMaMv1AZm9XmY@ z+A_t5sR!_MbanW@nO=SWB zIpZ`7i|3FT90H&t8@Apq#xl}V@JF(7RlXv0Oiav~fry3a{Ews)7g6#RRCmE3n{x5*0Lw@@C@Q*k zcw>O2pP*o^T-@>k*q zPfh|ODIPEc-Q4+Bv4dL4AZolk^eRj!b!}}ewu-_r_Z63tSV6cbfX3 z``av`)^_)9=t=hXV^aI>=>vs}Z>En{s5yLI20Xs|dtq_8l7!0JCIl88iC*VrTimFYZVP}h%BH3NL!g{tXc0`RCEv_paj%EM-5>r>zQK?X}dhkEh C>mG;z literal 0 HcmV?d00001 diff --git a/matrixConsole/Images.xcassets/AppIcon.appiconset/Icon-40@2x-1.png b/matrixConsole/Images.xcassets/AppIcon.appiconset/Icon-40@2x-1.png new file mode 100644 index 0000000000000000000000000000000000000000..712e94b116d03fba2cf8e810996aba29f04b6e3a GIT binary patch literal 6157 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 BH@yG= literal 0 HcmV?d00001 diff --git a/matrixConsole/Images.xcassets/AppIcon.appiconset/Icon-40@2x.png b/matrixConsole/Images.xcassets/AppIcon.appiconset/Icon-40@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..712e94b116d03fba2cf8e810996aba29f04b6e3a GIT binary patch literal 6157 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 BH@yG= literal 0 HcmV?d00001 diff --git a/matrixConsole/Images.xcassets/AppIcon.appiconset/Icon-40@3x.png b/matrixConsole/Images.xcassets/AppIcon.appiconset/Icon-40@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..9e551a2765a0ab42c1fb1e5493491fc9ae29306d GIT binary patch literal 8401 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 literal 0 HcmV?d00001 diff --git a/matrixConsole/Images.xcassets/AppIcon.appiconset/Icon-50.png b/matrixConsole/Images.xcassets/AppIcon.appiconset/Icon-50.png new file mode 100644 index 0000000000000000000000000000000000000000..58eefab92c9660a70e6b147533117071076ca05f GIT binary patch literal 4888 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 R#qYC*+5;`+Y9;HZ{{yL}39kSE literal 0 HcmV?d00001 diff --git a/matrixConsole/Images.xcassets/AppIcon.appiconset/Icon-50@2x.png b/matrixConsole/Images.xcassets/AppIcon.appiconset/Icon-50@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..dc80fdb775a0d3352fb942d57db00d897b75aa56 GIT binary patch literal 7164 zcmcI|WmH_v((d4Hfgr&N8k`9ZNpN=$?hs^vf#4Ph?(PsIxQ5^i!JWZ^!yrL|yA1Y` z_q<2Gv+n(O?_R6-?yi2So~~-$9j>Y@gM;}36953<$jM5oKYcC!By`lLx6^vECIEmb zX)7V2DkmX9qv`^(vbDDa0Az8pQ`|L)W=Z;CBlev2hADKGzuOy83OU+klNm9G4-pmg zW-Li+_$5*3BErzM>6y)b*f2k1&DTXoC*DWEpp(azCU~Aa(noP|CCqelue?I-{^rd0 zD#v|$<#vn=z>GkPXo_0_c-Npx7ju4P)z{0!bD@ewSIm`6&q-i0 zCw*zook25H#-n`Ov*i!>F;gKstNSc6EtB#sEOj)|nPiCktk5SZ9zQAa6#33436xin z%P>lucZX`}#h06i1qh*=V(@Vk8k%9&=$VMOPufO&msjZ9%VJy`Y#gwK0T7m{mt>Pw zNac!dW>h4%wk8G!LPL<)2<0DRz9dPJ%TKU2bq=O_B+CnmaP zp0Ph}U&LnSwm*4 z9;!)SJ=Q;(uJW8eAA4TNZOJ3dlQEbaab^*m;_TEc-*ptx&;YGVq^ShT$nVFg^O|~7{`<~4aK{&)9G~^zH$&rx5ApZ2hadz zwo7JJ`(`lDCB9(%OCSiwFD z!RrPeKl35*V|qY;!1e>YjqsPCA*{z}Kz=KZC?>0`P(n|^n8k>V--iyAM9D{(_)IGO ziy#$$ILxgF*NoaZNkBrKo-BSzcA^k_@`d{I(s0*6*WB|2MaI2^>_Gwx1W(@P2%jXM za1lj61-1M%^|>U;h@`r7mpGRcm(bG$`JxxIW9osDF`O3+~G6N}^Mmkmgq8 z*00q(sadz|Ws>(`kYF%o$Wi|?iBNPV|MGS4R~hrErh2z}p#_u$W=a|Ue6&g64#WA; zPW!o>C4;5+Cg~>P=8H{@AqnhY(*bk~3+^G(e$qzLBhA-ZZJO7wGBqS(~WH1#WVPN-oa&* zh|i5niNBKj02nk%F^X)}Itm}H-5T2xKYM>Bh86KSRVqiSptpvho2SR6(lT=s%<5Z? zTwbZYtW8}>S@Er6ui|K)c^-Mb;`{HKo8_756gz!$@9vln+t!UkRm+E;+tWp1ezErs zXc-bE-Ke3;p?ERMF=qXY{mx9j#TLbe%0X;GtXWz^Ex)4NE?E!o= z0w#7pO!BN~_-kmLcm`N(q*Qgd7zAE530-5E%tU@dKCVoA%w-HmB!nO40de)Sj`C47Q|S|Q(t4Uwkfq6Sx1~L zpP;f%PpQ(!*w09<><7izn0EQ9j;QgmNYQ0}iE_zWM8yaNly%g{xgA^7Qj}8sMh>j7 zn8KHH7;lvRhSmhD426>ik>}D%(K^JEY9wnkV)VlpqXm<7F8(VF;Aca@_kt*b_jEwD zcpIDA;q`+^rryqVxB;`fsbgz!%!A^EY;@6HQMc!zC$A^y)ciD-g!yUd@=8hLn6J06 zFNIBlQcY8wQ{6ab^&nO^$C%a6Z*|03HMBogP3mhkeQ^E$xGP~NYsWKtS3l$BaI>JZ zXEy6b^ntjFgF^4915ztnC2R1ysne}{B|0toQ*?XgKHtI8d2O1GPf<@xVcjoZmd5iT zemjItt$3y#!7K$rHwfn*8gN;Cib5jL@V-jBswVa5{ zfpG58LMB_rB|k7jA?8!TWPwVD%EQA&JD2h35FN!ZGjdjWO6x z#LjLzzR%jER7d1?YkLdSz@^pov~GBlP)Ap1p-RZe;lO#v_GWOcIK`-cW#&yWNU*Yu2 zJI*`(($~F^tK{cMe%u6S;5mA|9YYwRw{@AuFR%IUaJ>{E(?;CH0mx1Sd+3>a^E z9-?%AA%vdtf5e=0G=D){?L_Hxl~idYKrWUvyd1ANxai(s($LU|xL8;TsY^=#t^QOJ zrL%E$brRy_ba!{>a0haLT&y{{1qB5;xp+8vc-Ws1>|jqvS5psmNASyk82P6iNlUP~ zi>;HZEy$7Pk6lwUkejP09o-+Ie?9+br>m{iznL7tf4lYMAm^VNPHqk^&VSi{QWg0l z71C9=1cU6|{@8!R&m-~|^nVHeP4o{1z5kQKe+vIwK?3C9sTh%@=AUuPaK82JQe%IfV5Wrv)75;)3J*DRv%5$VwbMN*)Mc`xgep273seuW1 ze9Lh@Y`j`o-t1~UTc@aVw;Ib5gr#eI%{nSzBy_^apLo}5LofHK1T{g74jgO|XAw8> z8b4itMf|Be_0D3w5M2&6ToEZgJduu`jGhNal2JM0{|AT;C>!c>`s-~}b!jP!Ob%S$ zCXd~#Lhh0BOE7VHFb6p;W1`-5Eg%A!DRvYjqe!VO-Tn?%!{_Lo>jy6tG7ZJ0G$>Zi zrihtq25&pKNG2A4fpq@Ft8iCH<#3A?ISmuO-T$WWqPlir`GAU16Q@M_dId*~P!Do`v|{y0q2fp|FHm%OCR>H2R(8SRo4rPml|} z9mB4(7<}e_I>^!@zE41|&+}kKTskCy>(wB`64^ceoW9VL5TMaHC3u9}5q|!= z#o*`6419;{J$Y{G=&!nmIHr1lKsmV~gv~Bagxdjm7|Y!ClIske5Yx0((onKWqZl>JH*}-BES# zA&@Dlv74!I25*nKQTyN3hOpn;r-f4cHNE=DDiu|0JH>d_iAF7uLYs6u%-K;=Tt|G= z2=f~PSGQkIHnSVG>DuO@@HsA(Y-S09mmFIUw!F@F)^LUQxvrkrTcK}mM{4!l_hytV zLpWWlA@DNc)c_>dBNGkdSM}MwKO~pKnQ}@Z{BJf>4b2&27(&Uh-ItvEe<#?CU9N>v z@0tQ+t`8bvOKLKdn{g9cMdIJLWKf9$MBXi~C(pah8m9U_X+m&tuXoFct-VOIEVkv|{WZ+iyD?n`$@_I;fwjW6x|X$?v?_{mDwsZ5GUr4sTiuA$N@$)ytRjH1_&k zl+!3_&R8C}u5_Y($Q4wfTic}~9pn7oe=FU(?qY9t59WKdTr5DuVOs9iY+=Q$%D1#X z$ds$O^dk`Id)q<7qATLr*636Ni(HC8?;(u%;6R6k7e>DgH7O(l)yOGTb*o=uq0Gs4AJ)+!UFYVU)!Q^m@ijPJz$_8Nq#09rB_f59IOj$WYh3S2UJWQg>7BzJ2i?Su9tqH`v9 z(RCJ!w67wrR=ia#pGL8JcGhP0lHvI?YojK|1EGVXh05}jwb+wxr)Yh0U*sBN1S`O< zw4GZd?m`iOjB6;{eWjFM_@F+~$bOTfK+gbIfI|D1O*v}AW*bq5`gH{MvqQpBDttDw zFFYcKRn!dW>tAjz7eV*oXn0!|3^F>DM)q|f8y|58PNx2_4}~_6A*4soYy=gtB=J^A z2!m%7`7MWtc#%V+GaXyx_&wlJ+fReOVjj_gkK(@av%~wkGzwdUwoh^-Se|W0WBba7 zj3^O&oeS>Q!r&3LL|4>e?tmmL8QYku)tyxP0Po{YG~QkWDlP^MehTSL*`dBj0#NfN zF_RuLCsHV4%)pv%A9kHT(1U;QXO0AJ(*;<2@EX@Dc+fCX%vRR4!7ZZY{B` z5Xuq31CEY++7{I~OL&|w>@7AXQL(9bbUE{n&8Z~mO~8{OcdHk%qL*n@^l514_A99d zF5%KI)cP4APrKO;q~}}u)pH$#FU4YX$yZc&;a}=w>we~0Vf)qa1!$c$vmMy%&V0Bw z-w-ztYwu}_V}v4+oi@egv|Q+?AHmcPjy+A==g!j5YL;J0R^H8`GK*g)Vi{RYnC6Uc zJ#VRK7OYy;MAd*H}>8qaHW-b*rW1WA%%7d&nbs^Eq5E z(OARk_s1ym z7oj5W^I3Zfh~7Y3i#|$S#igV*Ho&k0NkRyLQXxJ)_NE$po-ID)Ikd*+am7F%-r+KG zfDEZG{G26h0JB(o;}XYVtJPu9@H<^Y!|WF_D_VP@AU2?d z|A`M>uxRKV!I4~!$2x{@a+~QrDlgmXrEzZLAC+wl4c|Jl6Ptb!(!fI>?V2FgYF+4l zWmfq5t!f-&T?L5I;{_3q!udU0{>hCzRBL`T6p;te#CO zaNaa}7MiB88Lhv8@4VC!ltzXByZ~R|T%6))uibhaR7|R9;g~7(1Y;0VP=AS0UdX91gyn{A8YBP<7@| z@VNdad_jrO%Qq#$VXrT0OqaPPE_l{d0>S3F+fWy54P!9Qu@V`R z&`r)%a?t=cEQnZjDR2=mnd_QT82-_}x+aIo26_&0fuhr7+{E*VHl)_P)bQbq@|G%P(o5#LZsnR(k)0M zDe&XH_xry4f6xD)=h^4%{hoKdYp=ET+0Q;N^mNq8h#83i005Z=SjFJ>DgC<<;@{q5 z=tIK+0Advw2&AV00X4O9-)I~0KQ5HjsyT%-;g)V+v*Zh z@yJF(l+HWxz=i~S@h5-CV?c!kZkT9V@b{ZNP{IRhEkH=e2tbxqF(n$s(Pw^6odC&J zNy|#)bD-yR5Kd?BD;3eX{Jb7~fw9+RII0Sl8&^-Rex5S$%9E~->8Jpclt7sjeTe%D zlZ41A%jO!O&H057^_R$gMFNNbj&Wh&GJO-ghMz|g+>tT$7rbzE&%4j$(%+n@sH#ew9_Nq z(<37t6V&`S8$aVSvYW3N9GkCJ4@8!SvXo-71ZPsF1Rv}01IqYnBrIB7_++tMEGR;@ z<^VHGuYj{HIjw2GY`31{ zr6N>;IrZDJ;@QkH=91L32g}HFNc0Wsaxlx8@nf4cJJv6{YtiS*$HnyMKHLtmnmOgH zN5Ebx5xkDp?fq8L%liZjLFsNZF5YZd@?WTVk4LZ$-6-0IdjT4=p}UW=FKLxyu&OfX z-pQZ9cJtW`Pn6b3MjSHG%JAN>Ed5hHA(n|SGP?(~PO>i*jua|S73lZw7jmLLqSESewH^2%F!jit zS%NGhp1;Gye!G%?iexHdO8#IY^L}eqO4y6LS#hbE&B1Pf7Zpz3$-|IXFfXK zo>vxJrks=aCD~6cvv?8gdt9yHpb|{sFVAy@b0WOFXSvuGPxC(*ws;0kuce zgdxHfl|~02mZ4odn!a2hE*q{agWOT9!Xr&iv9P!54rBE--Ze5acr&~#>XLZ`qoSK! z$9tR2#~M&BXuul%8ul9FnqeP^G|aA-(9u!2kG_Y#j(*Qb%=nYh+5HTobR&GDx5gXA z{-uY;(Z(6Zh|(5Ahtl&>XsL&>n_)msoW7)Syxx%MLVl1^pgnnD+&1%W=CX9p`s^Pe z;t+A5cruK6cylCmbbR!9k_NUrF85wKw`=%tyl=R4Sf*UOLVN7VB(007OZG@mpOKTl zaCNG2zrcDyT!c@&ilcbiiBOv+{ea&Mv7yw|HEdZX5wa@W{p6PE4{0=i`WYv zvgh~@L(!ou_;dJU5o!^Y5lp1tNVDln81WeS#a+c35fJecA!~O_H%uq4bBD+mv1t#~ z0F8vVkhWyG@Q!Hc0P_H@Q`5l3K;`=2y7JNEBPEik@D$Z7)%>mxT%97HQRUE#HLnMO z?{MFho6MQ8m9vypmu;8rP4iCUPM3ZB{^5LXVm#T+!XcnD&UM4NuCHQlH@rDbejzCS z%7Y*sRNRRlsS`;NrxR!2!`ov^id3khx^yjtI zuZRlTinNMItL%R9^sm_#l0KicCu3J?7d(33e9!vPG8EVg>Iq%Z-#+Ly9D223z9+p7 zU4Fgf{dv2g?ql6lQ&&LxPKR~7!glD{*(J^8@x}e~!PD}Sz|ErVl=aC?$?toMt^GId z010*}Temjb94B_k4;)C5UOpF9JyRhrsr&UZXZp`!&!q}DX~@Zl=V<+dv)bjBKGh0Q z($d%R|4^#eKU>~s<3v&|QHfK+bhMFVlE7s{Y-<*1@y06I_fkL^-fy9D4!p8(j>y%spDJ`Nu9bA8eP_RJWq5 zXy0fi>Mq}7(e38$;bzkb8X{U5N4+(`HhfYDK~2xH%sR{ITH_%y_qqi);tLxKlZzBI zytKY0OJwaPSf?p)*pigu35sBgoH#+8BcQDPnFCP+u7li;JkHsa_lZQqt)w4I<4Iou zMfDS0Tq?gV??m%-wJ%>-^7`1po5JF*AwR*fh1-Rle!G6+euzVd!+1L0+pWt#IaOe~ z#?ifGVHA;Km+YD1Eih@`;&i@G{QmBxsqzCulP49U7RL3i=#MvBAUCj^$mFk@34f3C z8Pje1NpBig+6nb1Z(;3s< zIi(qnIbox_27j~|25%(4*?Twk4l&_7DYiE{^$|9C44>b9DxVdQe&V{zKYa<$wq4k{ zy1ukr(cw*xc~3@=(3zbnNqJ%YU0177nd#(t ziE-A2`C#CtigTo!`q%hmMOL{Iud4N=!;-48g0b)-=b?x4qTVLxC(D*I4GDt^W zgA1Ecn_JD4n59wG*659<=EfmQR1^BJ>g(DaQ!~?<3K?sU9nVeJ`In`lWb2;!35BAT z6Su)hnTw5+Y}S2xDWAEGi!P?8k`?orKGio9zbxtq?hr)6kKl?8ue>+9<~}uvo|-K5 z%nJtP?B^Wjc6ZKXYX`wuQOq*pKSXDbc(+EHsdjs-ZBW5}ijU7yFX~Z{fU>0*JFi}? z1g%VF3HZufK#tv=@-|JoY<%P;gRVOfS*<@I-P&<2l&z^(&Bui^Uqj#ju<_Oj*OkY- zx$<{vJd2&l03pl~O$%KuOc`H-n`ek^7VSzrg=E`pdxl|1$U|_}>N~ga;A@_44}dLHKV6|HS^AuZw~~ zZ*%eIjQ+*{C-&cbJr@KTaa$J@%s~T=hN5nr{cZiPaQ=VB-&%5lzf=2_P)Rgi2K8WtqawV72A78E)(eSxCPY0&#LtsnR|9 zxt08`Tj(F78|Qlme%~i``*YE{i{Zgn`Q~*HFnAww(bA$|P7!|nxT6bMS6ge~;J_Jp zbKPw7G`I~<2rh+FDIH^o^M~-2rglWGRT|C&BKpR8o!yX1zw)SW+?<}4rR&bzqe_PGDHuo8(!rI9!Fe%z{xq*kifxp zc7ht%*)6dHx$vo}=v^yDM!W;axv1~lDQRd(8_ZVJeZ{Svr=1}|r1PD_=6hpfV{uLn zfY%iU%dK?i>0<=CZMR8ti1G39<@p$T-DxLh!Y_P~3L;X}OI262t@S*yeEo;_9HAFI zAwXMI70;>x)z!||tSyOJ1(%kT63BW1RX^mFnPgc|GxLV>Pg`;(~&(s;VlLCstN0a}8dR z)~!L>oN6&Sen;yg%U#ih)&e#ykUKm&1t%v@I_eAR!)9i_ZFWV|8ChCF5DP7Z>hY{2 zjX$@G>*^+75XS`m+`2oECK~xxH(Te;n>XmwT`OUF%oG86*tKvQNrZf8%2MpW&+SPv zk`zCyKo(*HRvms(?=2&ScqYj~BNLN!^J*vQ?Ixc+3Cmv*chSh6I2KWhTK9zW2Ct3& z=B)s3Ma6{=2@zvMW!B9z$bqy{#nQ0##r9BgLD?as=GROzYMIR{+ji`urA`8`gJo57 z*}#jM%~Hi-wkLpb0kb_wUhFCyI;91S;pFVjmJcvlx2S`Q&we4DOr8GZSH0-!=0--> zGTr3!{x*Ix6(%@-RV{K!d2DRVVZJ$l=jiYd)oIQlW^8<=Ch)kX7g?Knap6BUJZw8r zVda)AXaiRW`o)WOovN^EQt8e*l#j?rEGtoht92K=V{t8bIQp6lc#>0d^y!lvhte3m zs8dYLG(bZh-7fAn0q%5haep~@w%Cr7`(=_1M2WjJBHJrCq+{u`RcGg zN{ydwZ*IQiSKNKsW);@B~} zP&>fcpAg=(rE!I;Pm`BcR3ys`^bICnsKvHZ0iLva(QXUBeD#Xc?d&O}x7v*~R-GmE zqpzJA=WT8IGfE!GXYNSS;4k`0d2c1fytisnQ;%cL_4rn+uZfE49X_GJjxpBXiP(Bb z)u!meoq+uOJ=q0w`%Uo(P&5YLD6l97S!Pn0mxdnBAas2~D$C2YN7d4fxj+9b18NE>zwuiBOq4DkAmK4vKO(J331foKf8sM#p%AH8gRS?c zp$}IzWAczRGz3VSTH%z1_lymuG^cZ@-y&>F`t)augXy-9qA&t=Q{az6dSJbwHs zNzZ2%3hRoxd-!9v!I0c@H(f0F8Y3(tD{CQu^T4#?9$bMs(2^7YgTdnZ_3XhD6wFfW zJ+yg*^PrwmxpsQatref?_9kZ!(Ms7GaD?qz9Ol*(+}b$ zkQwG5+IgO-D@r>{<@kK$I@LWhE+M9@OH4vWrv~N+n|Wd<->SJeEZLx=(({0Cl$I;Q z$Z`6>P;v)AI!X6pX9h)(w64cvmC$cJ4$V zeHB4)IcXDJ-r@cdX!-J8jc-eU0bEC*(78ai1 zY|rcBtl_5oYEJF}0*18Ybnc&_HHM&EJ-M8S`^_yL){FbR{1Y^E^0numx^I6)!{bokVDRy4^ zGS3U54KXi>f#1J=Xy9d08SUb0QNc?%hE7=~kpsUk)7a!) JsZh3k_CL*isrmo_ literal 0 HcmV?d00001 diff --git a/matrixConsole/Images.xcassets/AppIcon.appiconset/Icon-57@2x.png b/matrixConsole/Images.xcassets/AppIcon.appiconset/Icon-57@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..8f09a3dbb73824ef7618460aa9f0f40d5b20dbd6 GIT binary patch literal 8094 zcmdUTWmsH6v*zIL!QI_8xCIGLa0u=;$l&e-cXtUv0|X~Pu)#fOaCd?;Lx3fp-23f) zcK_|4J{WFIW-Q z3(6wU#6%jGM1YsjBjwTr z4R-UEJ=g$HX9yq8n;mrYav_t1knLvWLo3uUtlQkX4>Xf3#N zs79-JR38WSgP{KAYQ)!#5u!ikGrmPchZ zD3jXQ5by>U77k`Au=TxNRZhqnvOKVi73!l0_(QGr->9d|XM7@9o&hh<%=9hbvcDYM zCgv7)Jri4YJ?&odY)=(P#T9U_WG-Lf_m|L%|9!?CE+vQMGI(9KqbTbVxY=bA68 zc{OB}S=p@HE)eC|7mDp5@&|1LlRYzv5w*Qoi1f`DBG4#&A79g&bb%zzFb)qwU(dorWj1H^rmP_m{q;T>PRG#ctVIPKNMXsjo@{A`Caf<;bctTh{C0A z@@IumA!BJ!lawLa$si^XTcR~kc?}byhR_syGZDWJ3r~7ufLR;%zR2wh$qE*~Vcr)+_|S-d-2J@7Stgg#Aie(%!sA2#bC4n>r6< z{`lP}SiMu5%=?dJMpMKJ)C?L(o8_7o|q3p6FMirZ7 z5uwGgG5~lf`v=*;H3MnpRoqcrwOJhF9^+irxYsyJgZ8Eq^&Cr*j${HDxryw3I_4)0 z>`Q1%xl0)y1IF2;$(o(#ore*W$Kon#&TA`+|L{Wq>Z zP9Wnm@-uoMKq4kch6=98dgd{Pw5LC8ABceIyM-YR~DfJW+sA2ZWkvLdo0>x z0Mne(HBCrHla4rfRbi$KeU?NMzw#3(1XOsFqReoTl0SlD3FE`x9^;?p|4CFiP)VaC zOLHkrHYTkx+bzj0!!7D6<$XDcrdTD47K#UNbBJ#NGzlt~z+l5n$TXB{NUuw~$RbE} zZ&bhpq`IK*Q3$N`FaP5T5r?24l!O+;8ithCYZl9Gh4&TprO~L&$Z;!k8#ZWN)^A%4 zGQRhwm!UVIFVHNWg(<&&Ps9ri z&ScI0oV{6mV|V^j^y}N=!Rf1?qtjK>!nOQ$Ds!HT1h%@ig)@PpTGqbY-?FsFIrhsE zB2|MEv}}4*zfQ*0C7=7RHFr#OVBIMAvUO>7p?0ZuDF!$_sXy&OcW&S%ZV@D$g|9*IzKAsW2Whb|ZHv%49DuT7# zXS`t(WE1e#ofFWBhW*KX>1%^)DYTe~%y$LvN(bxd`*{Z3YOQkj+*t#v;j3$P)^sRq z$!osVoYY(_GcCg}*EAp1L)I34W;hsH`1L2)AK0{x)~%gKbY+We1SUQ?A?3(?=|_xG zjlxP$O)wu~7;M}J8cecqn*uvDq{J;s_9+5;Ar8VOnHO zC0I}G!ZXZl`%Yb#i(ZJOP5410+AdnCjP?yC2I?AtZ%{$6=+^fZE^Gp#7WPxAHjRhv z-;}g2I9oXUIEl1QG@0_A@-rnVC7AME33mw`vE70j-rb-;n>c@Eb7h%vP>q_SKz z_G(O9_2uzp=))bnzqGP+K;KW;4TN8WaSXzA1oZ0$woUb>TYK-0V;c$b->0Z;(~+xz z8HN}rRRgC`c7D2j)`b1wS+4B1yh^@mBdTVM0L;4pa~>p?ca&#Th%34){mKw1I8Qdt z7N<5vt3u%9f#tcgRq8QJch?%gTWUyqkDa2+$;f?tC*5EC|+b0@cjbvNfhOzCl zSjNHLZKx5Gmzi^Cc*3*ttwMbHNqN7|xevb&@XF#Uk&x+i>hjIV;#h97bgbN%1!kIM zxMq5AEb4b#Lw=)v#edY5X8oY!SvPB_-DVGJemRzLP;lT`{L{4H>jYWRJuzSOcwt8<5QP#K{z}$K>Dk!j_6~Np1 z*25i`ZLwUy-p1a?-rC~pD5h1X*WKiAX?WPOfNK5Db+GzO@fWA=ithQE)C%<)w-&zU zeD{Z-gN*!(>bYv*g7+fd#q3hE-Qtb&`gw?0fnUy@{W<&cqjRC@#@W;JqoD(a11r`h z<}SIn5#fi$C-#$Hk-oRk6et!_1X2{{JBnj_7kgWw8rQZO9OpEF1WH9ww=clMl0>flVy{B2RoA+hcSo8UD*Cx zv+sIh4?4R#ri|P=L064qdw9Bfx+`_U#!hFhhjx&Wt%?leq4fpvitamy$wgu4!CfK6 zZz3VDwFBrNX^3FmdY;#}mxVuutw?xCQO?)S678uT2ZL+hJ9+PQHip(Y1B-qaT@{1- zR|-`EohjVNg!xZ-SFf3lXS#6ChrgM)1^GxAJY+%J+?4%lwmzMurtSppEEaHh3qzG} z9IZM?vakiviNnkiXl}*f?d0-`1^`68gmXf;;2+qRHAN{*20>ya{p3)eG{Xx1%X_I zIXS(&yg0mgIe>09oZN5UzUAcN;pE|Ae?_pn`#6KlyxE=IY5z&`Zys4IcMCT=7myv$ znd&dEnK{q{Bt}E?*U*0*|NKsno%MfPa(4e$vtAp>`L~9Xn}dtI8K9Gko0Yr!Uklv-GVq_W|A|*~v$J~j z#Xr92-}wKO{ZG8QEf55Jjf)1 zq&TW5=YMqyanxvY2nGOv+odQgrR5ECmgiNYJ%~4yDW7VrB`FoK)DUdm%VDl^%Adis z#1AIGSNb_%{KCZzPSGnd4~>cW!`5IfRiDX3pjBT)MUVqp+VGDQ914i?yJ-Ji;5{|M z;bU`uIyreh>E$(fdTMOojlvPRs#L^rPa6%Vjv`Bi#)CtXgfkqfP(;-q&B_C-kB#!i zlF0R)92FW(NGLjO-D?UWMW>!*Hh@nY!WIpW$`jW{Lz{$GmYth&aP&9G%W;x*-{u6AcPXd12}7|W%C*^OUirvmO8GdJm_zsLkf z(qyF%bR1h%v;2x-#r+)g45`Q!1Qr-}fGQ_rjJtf>1)NrDeAO%_VsK4E*j`ywas^a$ ztv-$kFBS(NEq3|c$HZ39B?+)bUwpq-6|@?C(|Ytd*B)t7^jf)fKgXe}V`8q#lFjVP zV0Z57!Fcu#MZk^5*}33`|IYEr$=bZGNv$M_iV(ppeFz^7%fy3Iq{vPj?Gu9q z;l+ZU1qOTFJ1M=M{w2h9vL}AyZ#Gk&Q)2gdhV?EX4%9Ex>PY0Eq?6Tl_f&?q+vIt# ztq8&n&$E?wuXP`Jsq(Y;#WYD;j*H#-Crb^bSHZ3Yp(ugiIO6j$&K|9h(iY#F!!3ag z|Lb&$n9H3H?tda}V&{KN~ zPw!UU)mpD7MI1!0E|W*N8m)b$+j8(;Re(qDKMoruYqih=8@OeWS&%(x8?TrTrmp60 zw)~h$uHvGaalkrJ-;)S0%8$+aS{;{Xn;qwIaa*76esyArKm71GUb6G)3G)S$c2j=^ ziTkg#IGs3uzmya7IyW-@7==l0l-u$`6x@`%UmD(Pk)3&lu);$xLfdeu?+Dr3t_o(; z&6Z1vBx%V&FIhFlE7r5sYNej@&ZdgbXu~xbt*x6$Mv4yCsm;K0?+rzOQrt})M?5u% zo$fulgD{$(#+|K)}1NCUVl(nK!O#SG02AFoxh^Amr@1HVeMEi~a z=*^M6^tHue^pkk;6a6 zZrr%k>^#5Xar|?H+Nj13kM0(d(d@joVupa5!KPor4GDUAYHcwKkc(h9YU9#Z3Tulw+XXa0|8(82p9rpd@05|Pz+npgNF?S3$EuSy_m53UyqsRNA5d^En3W1IfX_QG z&M(?_FgXqBYgwzOHUb~do}+0Ke#?`4q%Gi7YwkF;t}PS>+${%Qblu<4%EhTe)x;qK zu~z45B4>OOwnI|S5roFme+W(dXDI!D_bTR^1l*<*)`P}>?_d1Y%AomOIc7GBU%oF(Zfb34M3q7AH@&F zv4LUEFy)bi7xsT}3F^lXvuOj=Zp zF#NUWd1WkWBlgp2>#{W|P#PEiXzJ|&SwVJR;TOhx~Mb!?TuO z9Lz}QeUw3eioX%&blt5ejb(EwN52MExA}+o<7p|R=KY~_`yK(Oy(WLZw(iHhDUl1& ziPn+E*SJ6ofnC~+>sc@HGoI^y7h>haT&BS$K~J~ZbK!W?(BWNt?K7_>Go+1X2VL^V z&EBvs|MzKFSQ`DtErO$1D(^n>VT7RciFibFb{x{2v05P-XBo3gmRLIm=Q_1yf6k5{ zH?XFHYe|TGzOPX|M8Y5`J2oIge}BJV2=p0c=1mv%Jk&taih9S<>y5hmiU(^@9j^FS`jh7X5rdy z(X@q~pnPX3mooGpoZZYC#qO3YMmp#7MSU6<(4^@4*Q*g46~PH029yU&6mPoSUln%a zAV{|mak$@Jx^CXM=|m>}9wH{$7dwj1vzFY>t5Mc9d|jjB&tg8W-XKhd61n0va)S?( zv@7mCf}n*&jS6e zdrDHVXfQkS<9X-TRJG^?C5DOwN@8q*RTr82*FGeYU8X8dY!51b#Hp`hS!R=r8Flkk z8#r{mVxNh`p(CJOSY^m{EP>-b(Xg(Z9j^JX#S7~26IIs$8Kk_M#$*Jt@cZwg>Y zJXdvOeIrRZuL^^neFXocY&mad;>j#1LbEIqT+JWo9tT04;9uKiC3Les3mdl!hMXGL z(=vp!Bp-)amA~B&7CW;nfi1pEuk0%bvL@{br%^PagbRJl*uUJ*1s;#ULZ&sNfKxw0 ze#PV%jNKm14Nc_n&yjm?hMc!<1kN2JU-qEh%xJNa9KOOA>RiyH@c=erg|H3QYxJ2$ zjsCYf)KN8;H3U?(c;nMtT!(x~cat;NtPc%1v`sM(MJr$hqSi2yONDYliTy|2u1(ui z`m%4J*p5BC65RM11IMSvdpB-Tl^s#YZt8h)6ouyRfxbl+f7)#S##XI#5zFBuw;CN5 ziR+tE66bkLo(PL~3;w(f;yu}XibpP<7Efl)xDOODm0#^@6kz4>sn-f`9!nx((-1={ zdL~AxZtI~06)~h;IjDcviM0{N!Wu9x)huxN?u)B+A<;5Jr3bo6^rN-WK2(JC@2^?gaU?`dJ{j!$ZRqjGZ$Kx4Q4nQ zw1>Y*&(X)`z|)1vBb2ZpTVIwNHj0RMJ>D#&n@Xb{DU+K)aEabT!fxP7zdS$jcb_(n z<+c4@eO-i4-%;rsBJ! z?ZJkxi%cUsF?Q9gnkSUJ&KSg)=MtKU)v;GqyE7?E^$ z5XqPE`J+a4{IOcTu=dF{HhzBFQBA^N+cEOahTW;dpoiQGG6R-hW~@g1N@ym;z-q2X zIy-*xyZF~`=rJmv(3w(mvw^6HV?le|U`+oBO$F*m)VdD*H+25lZW+JD_765Lng1~R zO;=6OZ{gIEHMGjQJZ5ShW63%=mn$%|N&quV0(wX*W*lZRq)MKjmvYF0@0Hs^dWS`V zW=p{b$MS{*EJwO(hf7&cD&Uw^rA6n**2B2g?aZ}*F}WUj019helzMBa!a zSzB4PlX7ohCR>UO)5Y_n{Kss2G9BjsY zmVPWh478e6flZ0TPMQ#3&o%=IptDX7^CRh~5^cidBY1~@k3)iV*pmu8$=U4bNYp4% zfT%GpGSoV>9(PIeagh>}2$vTqAmFLsZ(dL*>Kfo#n#0(!R!lBB9UO89+k7^kN+qTS zR)3xZ-fwZ_sim&J~yVg4d{Yy6qmAle}Wcl4_Y~)8>0>$IE7$Kf1IG)BIwY zYWgPzIDIGisw2l7M5#1bX0aAf7s#hvTyqg#wS&YMED_scDfSkxet+TG02QZjAS zp!S&}u-0q3KhMP*NMQJ60H`sdw8vBkkJ{XgEbu#PUi?`x`lQiL8btD`sGG_S^=%lUEU4L!Xb)LKRTUxBybcs8k=e2)Q zmv}toWzQ7hO~^%A#Wn>FQ{Y`w>QVqUU0!bH)S7Evf}iV#R>ZW22Q4iZ|!rdp?xJX){q^fd$^71DJpY0*sXFS}cJ z0(+ho^8L=+kD0uWD=Ww(aVS!DXeZ$yy$LYk_m-zi4ILZbFS;LZT40)Le$XooW>42Q z!X)FPx)?=+E0l`zz8j$PBb1?};9)rD6gEub9;Fz>6vPsQq^c=)cjDhd;sk2 z1Ei?^@uvqv&l_vpXgw5m7m^z9d)yux%S z&J-$s&fET#DRa`oIV;^WA4`=g9i75Bn(T{=mMqxW&--jD zWV1wJntOH~zs1(NFDv(i+$k#${4f|XwoG5nq$2wGe!SnCNvvOm;@|OqRL$O#0ydci zwztH+^pG!ZD@m#%R!Yfb^kj59wpA zS3&g7Nwp&@mWA^=3`u#z8?S$4zDRi2`PKMDWLu{b_H-G#j4-LpIuE>4qNVF}cO5O6 zbpz$E+W>eC1beL!9SsCTnILsu#5*v{Qp_i3sO;Qz@q(PxWwNbPsMkt KvUSp?q5lgHR#nvi literal 0 HcmV?d00001 diff --git a/matrixConsole/Images.xcassets/AppIcon.appiconset/Icon-60@2x.png b/matrixConsole/Images.xcassets/AppIcon.appiconset/Icon-60@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..9e551a2765a0ab42c1fb1e5493491fc9ae29306d GIT binary patch literal 8401 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 literal 0 HcmV?d00001 diff --git a/matrixConsole/Images.xcassets/AppIcon.appiconset/Icon-60@3x.png b/matrixConsole/Images.xcassets/AppIcon.appiconset/Icon-60@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..881660c8e206b180cf19e71f01ca5b83e4a381f9 GIT binary patch literal 11463 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 Oc`K(XTPkh(@jn0^;JDHN literal 0 HcmV?d00001 diff --git a/matrixConsole/Images.xcassets/AppIcon.appiconset/Icon-72.png b/matrixConsole/Images.xcassets/AppIcon.appiconset/Icon-72.png new file mode 100644 index 0000000000000000000000000000000000000000..fbd0de55da6dd122496d7b317ab0cc0cf4166bde GIT binary patch literal 5735 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 WA)W7rJFUN4cX=6Q=@O||Z~h0Bs-&<0 literal 0 HcmV?d00001 diff --git a/matrixConsole/Images.xcassets/AppIcon.appiconset/Icon-72@2x.png b/matrixConsole/Images.xcassets/AppIcon.appiconset/Icon-72@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..2ba37c38459c78dd662a45ab4491c74acf5abf4f GIT binary patch literal 9430 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 literal 0 HcmV?d00001 diff --git a/matrixConsole/Images.xcassets/AppIcon.appiconset/Icon-76@2x.png b/matrixConsole/Images.xcassets/AppIcon.appiconset/Icon-76@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..e30f4ad33e42565eae31f78438d16b5d75d6609d GIT binary patch literal 9983 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 literal 0 HcmV?d00001 diff --git a/matrixConsole/Images.xcassets/LaunchImage.launchimage/Contents.json b/matrixConsole/Images.xcassets/LaunchImage.launchimage/Contents.json new file mode 100644 index 000000000..df7d17841 --- /dev/null +++ b/matrixConsole/Images.xcassets/LaunchImage.launchimage/Contents.json @@ -0,0 +1,107 @@ +{ + "images" : [ + { + "orientation" : "portrait", + "idiom" : "iphone", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "filename" : "launch@2x-1.png", + "scale" : "2x" + }, + { + "extent" : "full-screen", + "idiom" : "iphone", + "subtype" : "retina4", + "filename" : "launch-568h@2x-1.png", + "minimum-system-version" : "7.0", + "orientation" : "portrait", + "scale" : "2x" + }, + { + "orientation" : "portrait", + "idiom" : "ipad", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "filename" : "Default-Portrait~ipad.png", + "scale" : "1x" + }, + { + "orientation" : "landscape", + "idiom" : "ipad", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "filename" : "Default-Landscape~ipad.png", + "scale" : "1x" + }, + { + "orientation" : "portrait", + "idiom" : "ipad", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "filename" : "Default-Portrait@2x~ipad.png", + "scale" : "2x" + }, + { + "orientation" : "landscape", + "idiom" : "ipad", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "filename" : "Default-Landscape@2x~ipad.png", + "scale" : "2x" + }, + { + "orientation" : "portrait", + "idiom" : "iphone", + "extent" : "full-screen", + "filename" : "launch.png", + "scale" : "1x" + }, + { + "orientation" : "portrait", + "idiom" : "iphone", + "extent" : "full-screen", + "filename" : "launch@2x.png", + "scale" : "2x" + }, + { + "orientation" : "portrait", + "idiom" : "iphone", + "extent" : "full-screen", + "filename" : "launch-568h@2x.png", + "subtype" : "retina4", + "scale" : "2x" + }, + { + "orientation" : "portrait", + "idiom" : "ipad", + "extent" : "to-status-bar", + "filename" : "Default-Portrait.png", + "scale" : "1x" + }, + { + "orientation" : "landscape", + "idiom" : "ipad", + "extent" : "to-status-bar", + "filename" : "Default-Landscape.png", + "scale" : "1x" + }, + { + "orientation" : "portrait", + "idiom" : "ipad", + "extent" : "to-status-bar", + "filename" : "Default-Portrait@2x.png", + "scale" : "2x" + }, + { + "orientation" : "landscape", + "idiom" : "ipad", + "extent" : "to-status-bar", + "filename" : "Default-Landscape@2x.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/matrixConsole/Images.xcassets/LaunchImage.launchimage/Default-Landscape.png b/matrixConsole/Images.xcassets/LaunchImage.launchimage/Default-Landscape.png new file mode 100644 index 0000000000000000000000000000000000000000..442664414feea5a20807855d6986cb3d689aa9bb GIT binary patch literal 33325 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 J-YUv({{ixI-+2H4 literal 0 HcmV?d00001 diff --git a/matrixConsole/Images.xcassets/LaunchImage.launchimage/Default-Landscape@2x.png b/matrixConsole/Images.xcassets/LaunchImage.launchimage/Default-Landscape@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..b7c65c9766aad127c60cd85564006f2ece6bbfdd GIT binary patch literal 74252 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®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≺7kTNe6>u&dv{& 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 literal 0 HcmV?d00001 diff --git a/matrixConsole/Images.xcassets/LaunchImage.launchimage/Default-Landscape~ipad.png b/matrixConsole/Images.xcassets/LaunchImage.launchimage/Default-Landscape~ipad.png new file mode 100644 index 0000000000000000000000000000000000000000..9b96538702dc6d9a87e48f874c7bdd1fd03f2e2d GIT binary patch literal 33543 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%0Dqd7%0OO&t&i6OfuJtTggZtz}X&P5%i|{WR9Hf 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 l)VbKVbj> literal 0 HcmV?d00001 diff --git a/matrixConsole/Images.xcassets/LaunchImage.launchimage/Default-Portrait@2x.png b/matrixConsole/Images.xcassets/LaunchImage.launchimage/Default-Portrait@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..3d89182132e692d4df9366aa9155e2e64ff3a99f GIT binary patch literal 76962 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 literal 0 HcmV?d00001 diff --git a/matrixConsole/Images.xcassets/LaunchImage.launchimage/Default-Portrait@2x~ipad.png b/matrixConsole/Images.xcassets/LaunchImage.launchimage/Default-Portrait@2x~ipad.png new file mode 100644 index 0000000000000000000000000000000000000000..6f23fa9d4d72b31edfc43f2c8f94cb1fc820b580 GIT binary patch literal 77394 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 literal 0 HcmV?d00001 diff --git a/matrixConsole/Images.xcassets/LaunchImage.launchimage/Default-Portrait~ipad.png b/matrixConsole/Images.xcassets/LaunchImage.launchimage/Default-Portrait~ipad.png new file mode 100644 index 0000000000000000000000000000000000000000..7bde9791bfa6ad7df737799e01c106d26580ec39 GIT binary patch literal 34198 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 YJH=@B!?jxuqrhv=Zdb>`o!&A31-Tp88~^|S literal 0 HcmV?d00001 diff --git a/matrixConsole/Images.xcassets/LaunchImage.launchimage/launch-568h@2x-1.png b/matrixConsole/Images.xcassets/LaunchImage.launchimage/launch-568h@2x-1.png new file mode 100644 index 0000000000000000000000000000000000000000..fa589947efab716e1593bde0bce5a7065528a330 GIT binary patch literal 30909 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 DYq!k2 literal 0 HcmV?d00001 diff --git a/matrixConsole/Images.xcassets/LaunchImage.launchimage/launch@2x.png b/matrixConsole/Images.xcassets/LaunchImage.launchimage/launch@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..b8db7b6414986ead2ff5ae9059d721a6e0e4cba7 GIT binary patch literal 28058 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 DYq!k2 literal 0 HcmV?d00001 diff --git a/matrixConsole/Info.plist b/matrixConsole/Info.plist new file mode 100644 index 000000000..fda320dd4 --- /dev/null +++ b/matrixConsole/Info.plist @@ -0,0 +1,57 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + org.matrix.$(PRODUCT_NAME:rfc1034identifier) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UIStatusBarTintParameters + + UINavigationBar + + Style + UIBarStyleDefault + Translucent + + + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/matrixConsole/MatrixHandler.h b/matrixConsole/MatrixHandler.h new file mode 100644 index 000000000..36a715503 --- /dev/null +++ b/matrixConsole/MatrixHandler.h @@ -0,0 +1,52 @@ +/* + Copyright 2014 OpenMarket 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 + +extern NSString *const kMatrixHandlerUnsupportedMessagePrefix; + +@interface MatrixHandler : NSObject + +@property (strong, nonatomic) MXRestClient *mxRestClient; +@property (strong, nonatomic) MXSession *mxSession; + +@property (strong, nonatomic) NSString *homeServerURL; +@property (strong, nonatomic) NSString *homeServer; +@property (strong, nonatomic) NSString *userLogin; +@property (strong, nonatomic) NSString *userId; +@property (strong, nonatomic) NSString *accessToken; + +// Matrix user's settings +@property (strong, nonatomic) NSString *userDisplayName; +@property (strong, nonatomic) NSString *userPictureURL; + +@property (nonatomic,readonly) BOOL isLogged; +@property (nonatomic,readonly) BOOL isInitialSyncDone; + ++ (MatrixHandler *)sharedHandler; + +- (void)logout; + +// Flush and restore Matrix data +- (void)forceInitialSync; + +- (void)enableEventsNotifications:(BOOL)isEnabled; + +- (BOOL)isAttachment:(MXEvent*)message; +- (BOOL)isNotification:(MXEvent*)message; +- (NSString*)displayTextFor:(MXEvent*)message inSubtitleMode:(BOOL)isSubtitle; + +@end diff --git a/matrixConsole/MatrixHandler.m b/matrixConsole/MatrixHandler.m new file mode 100644 index 000000000..81f29d3e1 --- /dev/null +++ b/matrixConsole/MatrixHandler.m @@ -0,0 +1,629 @@ +/* + Copyright 2014 OpenMarket 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 "MatrixHandler.h" +#import "AppDelegate.h" +#import "AppSettings.h" +#import "CustomAlert.h" + +NSString *const kMatrixHandlerUnsupportedMessagePrefix = @"UNSUPPORTED MSG: "; + +static MatrixHandler *sharedHandler = nil; + +@interface MatrixHandler () { + // We will notify user only once on session failure + BOOL notifyOpenSessionFailure; + + // Handle user's settings change + id roomMembersListener; + // Handle events notification + id eventsListener; +} + +@property (nonatomic,readwrite) BOOL isInitialSyncDone; +@property (strong, nonatomic) CustomAlert *mxNotification; + +@end + +@implementation MatrixHandler + +@synthesize homeServerURL, homeServer, userLogin, userId, accessToken; +@synthesize userDisplayName, userPictureURL; + ++ (MatrixHandler *)sharedHandler { + @synchronized(self) { + if(sharedHandler == nil) + { + sharedHandler = [[super allocWithZone:NULL] init]; + } + } + return sharedHandler; +} + +#pragma mark - + +-(MatrixHandler *)init { + if (self = [super init]) { + _isInitialSyncDone = NO; + notifyOpenSessionFailure = YES; + + // Read potential homeserver url in shared defaults object + if (self.homeServerURL) { + self.mxRestClient = [[MXRestClient alloc] initWithHomeServer:self.homeServerURL]; + + if (self.accessToken) { + [self openSession]; + } + } + // The app will look for user's display name in incoming messages, it must not be nil. + if (self.userDisplayName == nil) { + self.userDisplayName = @""; + } + + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onAppDidEnterBackground) name:UIApplicationDidEnterBackgroundNotification object:nil]; + } + return self; +} + +- (void)openSession { + + MXCredentials *credentials = [[MXCredentials alloc] init]; + credentials.homeServer = self.homeServerURL; + credentials.userId = self.userId; + credentials.accessToken = self.accessToken; + + self.mxRestClient = [[MXRestClient alloc] initWithCredentials:credentials]; + if (self.mxRestClient) { + // Request user's display name + [self.mxRestClient displayNameForUser:self.userId success:^(NSString *displayname) { + self.userDisplayName = displayname; + } failure:^(NSError *error) { + NSLog(@"Get displayName failed: %@", error); + //Alert user + [[AppDelegate theDelegate] showErrorAsAlert:error]; + }]; + // Request user's avatar + [self.mxRestClient avatarUrlForUser:self.userId success:^(NSString *avatar_url) { + self.userPictureURL = avatar_url; + } failure:^(NSError *error) { + NSLog(@"Get picture url failed: %@", error); + //Alert user + [[AppDelegate theDelegate] showErrorAsAlert:error]; + }]; + + self.mxSession = [[MXSession alloc] initWithMatrixRestClient:self.mxRestClient]; + // Check here whether the app user wants to display all the events + if ([[AppSettings sharedSettings] displayAllEvents]) { + // Override events filter to retrieve all the events + self.mxSession.eventsFilterForMessages = @[ + kMXEventTypeStringRoomName, + kMXEventTypeStringRoomTopic, + kMXEventTypeStringRoomMember, + kMXEventTypeStringRoomCreate, + kMXEventTypeStringRoomJoinRules, + kMXEventTypeStringRoomPowerLevels, + kMXEventTypeStringRoomAddStateLevel, + kMXEventTypeStringRoomSendEventLevel, + kMXEventTypeStringRoomOpsLevel, + kMXEventTypeStringRoomAliases, + kMXEventTypeStringRoomMessage, + kMXEventTypeStringRoomMessageFeedback, + kMXEventTypeStringPresence + ]; + } + // Launch mxSession + [self.mxSession start:^{ + self.isInitialSyncDone = YES; + + // Register listener to update user's information + roomMembersListener = [self.mxSession listenToEventsOfTypes:@[kMXEventTypeStringPresence] onEvent:^(MXEvent *event, MXEventDirection direction, id customObject) { + // Consider only live events + if (direction == MXEventDirectionForwards) { + // Consider only events from app user + if ([event.userId isEqualToString:self.userId]) { + // Update local storage + if (![self.userDisplayName isEqualToString:event.content[@"displayname"]]) { + self.userDisplayName = event.content[@"displayname"]; + } + if (![self.userPictureURL isEqualToString:event.content[@"avatar_url"]]) { + self.userPictureURL = event.content[@"avatar_url"]; + } + } + } + }]; + + // Check whether the app user wants notifications on new events + if ([[AppSettings sharedSettings] enableNotifications]) { + [self enableEventsNotifications:YES]; + } + } failure:^(NSError *error) { + NSLog(@"Initial Sync failed: %@", error); + if (notifyOpenSessionFailure) { + //Alert user only once + notifyOpenSessionFailure = NO; + [[AppDelegate theDelegate] showErrorAsAlert:error]; + } + + // Postpone a new attempt in 10 sec + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + [self openSession]; + }); + }]; + } +} + +- (void)closeSession { + if (eventsListener) { + [self.mxSession removeListener:eventsListener]; + eventsListener = nil; + } + if (roomMembersListener) { + [self.mxSession removeListener:roomMembersListener]; + roomMembersListener = nil; + } + [self.mxSession close]; + self.mxSession = nil; + + [self.mxRestClient close]; + if (self.homeServerURL) { + self.mxRestClient = [[MXRestClient alloc] initWithHomeServer:self.homeServerURL]; + } else { + self.mxRestClient = nil; + } + + self.isInitialSyncDone = NO; + notifyOpenSessionFailure = YES; +} + +- (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; + + [self closeSession]; + self.mxSession = nil; + + if (self.mxNotification) { + [self.mxNotification dismiss:NO]; + self.mxNotification = nil; + } +} + +- (void)onAppDidEnterBackground { + // Hide potential notification + if (self.mxNotification) { + [self.mxNotification dismiss:NO]; + self.mxNotification = nil; + } +} + +#pragma mark - + +- (BOOL)isLogged { + return (self.accessToken != nil); +} + +- (void)logout { + // Reset access token (mxSession is closed by setter) + self.accessToken = nil; + + // Reset local storage of user's settings + self.userDisplayName = @""; + self.userPictureURL = nil; +} + +- (void)forceInitialSync { + [self closeSession]; + notifyOpenSessionFailure = NO; + if (self.accessToken) { + [self openSession]; + } +} + +- (void)enableEventsNotifications:(BOOL)isEnabled { + if (isEnabled) { + // Register events listener + eventsListener = [self.mxSession listenToEventsOfTypes:self.mxSession.eventsFilterForMessages onEvent:^(MXEvent *event, MXEventDirection direction, id customObject) { + // Consider only live event (Ignore presence event) + if (direction == MXEventDirectionForwards && (event.eventType != MXEventTypePresence)) { + // If we are running on background, show a local notif + if (UIApplicationStateBackground == [UIApplication sharedApplication].applicationState) + { + UILocalNotification *localNotification = [[UILocalNotification alloc] init]; + localNotification.fireDate = [NSDate dateWithTimeIntervalSinceNow:0]; + localNotification.hasAction = YES; + [localNotification setAlertBody:[self displayTextFor:event inSubtitleMode:YES]]; + [[UIApplication sharedApplication] scheduleLocalNotification:localNotification]; + } else if ([[AppDelegate theDelegate].masterTabBarController.visibleRoomId isEqualToString:event.roomId] == NO) { + // The concerned room is not presently visible, we display a notification by removing existing one (if any) + if (self.mxNotification) { + [self.mxNotification dismiss:NO]; + } + + self.mxNotification = [[CustomAlert alloc] initWithTitle:[self.mxSession room:event.roomId].state.displayname + message:[self displayTextFor:event inSubtitleMode:YES] + style:CustomAlertStyleAlert]; + self.mxNotification.cancelButtonIndex = [self.mxNotification addActionWithTitle:@"OK" + style:CustomAlertActionStyleDefault + handler:^(CustomAlert *alert) { + [MatrixHandler sharedHandler].mxNotification = nil; + }]; + [self.mxNotification addActionWithTitle:@"View" + style:CustomAlertActionStyleDefault + handler:^(CustomAlert *alert) { + [MatrixHandler sharedHandler].mxNotification = nil; + // Show the room + [[AppDelegate theDelegate].masterTabBarController showRoom:event.roomId]; + }]; + + [self.mxNotification showInViewController:[[AppDelegate theDelegate].masterTabBarController selectedViewController]]; + } + } + }]; + } else { + if (eventsListener) { + [self.mxSession removeListener:eventsListener]; + eventsListener = nil; + } + if (self.mxNotification) { + [self.mxNotification dismiss:NO]; + self.mxNotification = nil; + } + } +} + +#pragma mark - Properties + +- (NSString *)homeServerURL { + return [[NSUserDefaults standardUserDefaults] objectForKey:@"homeserverurl"]; +} + +- (void)setHomeServerURL:(NSString *)inHomeserverURL { + if (inHomeserverURL.length) { + [[NSUserDefaults standardUserDefaults] setObject:inHomeserverURL forKey:@"homeserverurl"]; + self.mxRestClient = [[MXRestClient alloc] initWithHomeServer:inHomeserverURL]; + } else { + [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"homeserverurl"]; + // Reinitialize matrix handler + [self logout]; + } + [[NSUserDefaults standardUserDefaults] synchronize]; +} + +- (NSString *)homeServer { + return [[NSUserDefaults standardUserDefaults] objectForKey:@"homeserver"]; +} + +- (void)setHomeServer:(NSString *)inHomeserver { + if (inHomeserver.length) { + [[NSUserDefaults standardUserDefaults] setObject:inHomeserver forKey:@"homeserver"]; + } else { + [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"homeserver"]; + } + [[NSUserDefaults standardUserDefaults] synchronize]; +} + +- (NSString *)userLogin { + return [[NSUserDefaults standardUserDefaults] objectForKey:@"userlogin"]; +} + +- (void)setUserLogin:(NSString *)inUserLogin { + if (inUserLogin.length) { + [[NSUserDefaults standardUserDefaults] setObject:inUserLogin forKey:@"userlogin"]; + } else { + [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"userlogin"]; + } + [[NSUserDefaults standardUserDefaults] synchronize]; +} + +- (NSString *)userId { + return [[NSUserDefaults standardUserDefaults] objectForKey:@"userid"]; +} + +- (void)setUserId:(NSString *)inUserId { + if (inUserId.length) { + [[NSUserDefaults standardUserDefaults] setObject:inUserId forKey:@"userid"]; + } else { + [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"userid"]; + } + [[NSUserDefaults standardUserDefaults] synchronize]; +} + +- (NSString *)accessToken { + return [[NSUserDefaults standardUserDefaults] objectForKey:@"accesstoken"]; +} + +- (void)setAccessToken:(NSString *)inAccessToken { + if (inAccessToken.length) { + [[NSUserDefaults standardUserDefaults] setObject:inAccessToken forKey:@"accesstoken"]; + [self openSession]; + } else { + [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"accesstoken"]; + [self closeSession]; + } + [[NSUserDefaults standardUserDefaults] synchronize]; +} + +#pragma mark - Matrix user's settings + +- (NSString *)userDisplayName { + return [[NSUserDefaults standardUserDefaults] objectForKey:@"userdisplayname"]; +} + +- (void)setUserDisplayName:(NSString *)inUserDisplayName { + if ([inUserDisplayName isEqual:[NSNull null]] == NO && inUserDisplayName.length) { + [[NSUserDefaults standardUserDefaults] setObject:inUserDisplayName forKey:@"userdisplayname"]; + } else { + // the app will look for this display name in incoming messages, it must not be nil. + [[NSUserDefaults standardUserDefaults] setObject:@"" forKey:@"userdisplayname"]; + } + [[NSUserDefaults standardUserDefaults] synchronize]; +} + +- (NSString *)userPictureURL { + return [[NSUserDefaults standardUserDefaults] objectForKey:@"userpictureurl"]; +} + +- (void)setUserPictureURL:(NSString *)inUserPictureURL { + if ([inUserPictureURL isEqual:[NSNull null]] == NO && inUserPictureURL.length) { + [[NSUserDefaults standardUserDefaults] setObject:inUserPictureURL forKey:@"userpictureurl"]; + } else { + [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"userpictureurl"]; + } + [[NSUserDefaults standardUserDefaults] synchronize]; +} + +#pragma mark - messages handler + +- (BOOL)isAttachment:(MXEvent*)message { + if (message.eventType == MXEventTypeRoomMessage) { + NSString *msgtype = message.content[@"msgtype"]; + if ([msgtype isEqualToString:kMXMessageTypeImage] + || [msgtype isEqualToString:kMXMessageTypeAudio] + || [msgtype isEqualToString:kMXMessageTypeVideo] + || [msgtype isEqualToString:kMXMessageTypeLocation]) { + return YES; + } + } + return NO; +} + +- (BOOL)isNotification:(MXEvent*)message { + // We consider as notification mxEvent which is not a text message or an attachment + if (message.eventType == MXEventTypeRoomMessage) { + NSString *msgtype = message.content[@"msgtype"]; + if ([msgtype isEqualToString:kMXMessageTypeEmote]) { + return YES; + } + return NO; + } + return YES; +} + +- (NSString*)displayTextFor:(MXEvent*)message inSubtitleMode:(BOOL)isSubtitle { + NSString *displayText = nil; + // Retrieve roomData related to the message + MXRoom *room = [self.mxSession room:message.roomId]; + // Prepare display name for concerned users + NSString *memberDisplayName = [room.state memberName:message.userId]; + NSString *targetDisplayName = nil; + if (message.stateKey) { + targetDisplayName = [room.state memberName:message.stateKey]; + } + + switch (message.eventType) { + case MXEventTypeRoomName: { + displayText = [NSString stringWithFormat:@"%@ changed the room name to: %@", memberDisplayName, message.content[@"name"]]; + break; + } + case MXEventTypeRoomTopic: { + displayText = [NSString stringWithFormat:@"%@ changed the topic to: %@", memberDisplayName, message.content[@"topic"]]; + break; + } + case MXEventTypeRoomMember: { + // Presently only change on membership, display name and avatar are supported + + // Retrieve membership + NSString* membership = message.content[@"membership"]; + NSString *prevMembership = nil; + if (message.prevContent) { + prevMembership = message.prevContent[@"membership"]; + } + + // Check whether the membership is unchanged + if (prevMembership && membership && [membership isEqualToString:prevMembership]) { + // Check whether the display name has been changed + NSString *displayname = message.content[@"displayname"]; + NSString *prevDisplayname = message.prevContent[@"displayname"]; + if (!displayname.length) { + displayname = nil; + } + if (!prevDisplayname.length) { + prevDisplayname = nil; + } + if ((displayname || prevDisplayname) && ([displayname isEqualToString:prevDisplayname] == NO)) { + displayText = [NSString stringWithFormat:@"%@ changed their display name from %@ to %@", message.userId, prevDisplayname, displayname]; + } + + // Check whether the avatar has been changed + NSString *avatar = message.content[@"avatar_url"]; + NSString *prevAvatar = message.prevContent[@"avatar_url"]; + if (!avatar.length) { + avatar = nil; + } + if (!prevAvatar.length) { + prevAvatar = nil; + } + if ((prevAvatar || avatar) && ([avatar isEqualToString:prevAvatar] == NO)) { + if (displayText) { + displayText = [NSString stringWithFormat:@"%@ (picture profile was changed too)", displayText]; + } else { + displayText = [NSString stringWithFormat:@"%@ changed their picture profile", memberDisplayName]; + } + } + } else { + // Consider here a membership change + if ([membership isEqualToString:@"invite"]) { + displayText = [NSString stringWithFormat:@"%@ invited %@", memberDisplayName, targetDisplayName]; + } else if ([membership isEqualToString:@"join"]) { + displayText = [NSString stringWithFormat:@"%@ joined", memberDisplayName]; + } else if ([membership isEqualToString:@"leave"]) { + if ([message.userId isEqualToString:message.stateKey]) { + displayText = [NSString stringWithFormat:@"%@ left", memberDisplayName]; + } else if (prevMembership) { + if ([prevMembership isEqualToString:@"join"] || [prevMembership isEqualToString:@"invite"]) { + displayText = [NSString stringWithFormat:@"%@ kicked %@", memberDisplayName, targetDisplayName]; + if (message.content[@"reason"]) { + displayText = [NSString stringWithFormat:@"%@: %@", displayText, message.content[@"reason"]]; + } + } else if ([prevMembership isEqualToString:@"ban"]) { + displayText = [NSString stringWithFormat:@"%@ unbanned %@", memberDisplayName, targetDisplayName]; + } + } + } else if ([membership isEqualToString:@"ban"]) { + displayText = [NSString stringWithFormat:@"%@ banned %@", memberDisplayName, targetDisplayName]; + if (message.content[@"reason"]) { + displayText = [NSString stringWithFormat:@"%@: %@", displayText, message.content[@"reason"]]; + } + } + } + break; + } + case MXEventTypeRoomCreate: { + NSString *creatorId = message.content[@"creator"]; + if (creatorId) { + displayText = [NSString stringWithFormat:@"%@ created the room", [room.state memberName:creatorId]]; + } + break; + } + case MXEventTypeRoomJoinRules: { + NSString *joinRule = message.content[@"join_rule"]; + if (joinRule) { + displayText = [NSString stringWithFormat:@"The join rule is: %@", joinRule]; + } + break; + } + case MXEventTypeRoomPowerLevels: { + displayText = @"The power level of room members are:"; + NSDictionary *users = message.content[@"users"]; + for (NSString *key in users.allKeys) { + displayText = [NSString stringWithFormat:@"%@\r\n\u2022 %@: %@", displayText, key, [users objectForKey:key]]; + } + if (message.content[@"users_default"]) { + displayText = [NSString stringWithFormat:@"%@\r\n\u2022 %@: %@", displayText, @"default", message.content[@"users_default"]]; + } + + displayText = [NSString stringWithFormat:@"%@\r\nThe minimum power levels that a user must have before acting are:", displayText]; + if (message.content[@"ban"]) { + displayText = [NSString stringWithFormat:@"%@\r\n\u2022 ban: %@", displayText, message.content[@"ban"]]; + } + if (message.content[@"kick"]) { + displayText = [NSString stringWithFormat:@"%@\r\n\u2022 kick: %@", displayText, message.content[@"kick"]]; + } + if (message.content[@"redact"]) { + displayText = [NSString stringWithFormat:@"%@\r\n\u2022 redact: %@", displayText, message.content[@"redact"]]; + } + + displayText = [NSString stringWithFormat:@"%@\r\nThe minimum power levels related to events are:", displayText]; + NSDictionary *events = message.content[@"events"]; + for (NSString *key in events.allKeys) { + displayText = [NSString stringWithFormat:@"%@\r\n\u2022 %@: %@", displayText, key, [events objectForKey:key]]; + } + if (message.content[@"events_default"]) { + displayText = [NSString stringWithFormat:@"%@\r\n\u2022 %@: %@", displayText, @"events_default", message.content[@"events_default"]]; + } + if (message.content[@"state_default"]) { + displayText = [NSString stringWithFormat:@"%@\r\n\u2022 %@: %@", displayText, @"state_default", message.content[@"state_default"]]; + } + break; + } +// case MXEventTypeRoomAddStateLevel: { +// NSString *minLevel = message.content[@"level"]; +// if (minLevel) { +// displayText = [NSString stringWithFormat:@"The minimum power level a user needs to add state is: %@", minLevel]; +// } +// break; +// } +// case MXEventTypeRoomSendEventLevel: { +// NSString *minLevel = message.content[@"level"]; +// if (minLevel) { +// displayText = [NSString stringWithFormat:@"The minimum power level a user needs to send an event is: %@", minLevel]; +// } +// break; +// } +// case MXEventTypeRoomOpsLevel: { +// displayText = @"The minimum power levels that a user must have before acting are:"; +// for (NSString *key in message.content.allKeys) { +// displayText = [NSString stringWithFormat:@"%@\r\n%@:%@", displayText, key, [message.content objectForKey:key]]; +// } +// break; +// } + case MXEventTypeRoomAliases: { + NSArray *aliases = message.content[@"aliases"]; + if (aliases) { + displayText = [NSString stringWithFormat:@"The room aliases are: %@", aliases]; + } + break; + } + case MXEventTypeRoomMessage: { + NSString *msgtype = message.content[@"msgtype"]; + if ([msgtype isEqualToString:kMXMessageTypeText]) { + displayText = message.content[@"body"]; + } else if ([msgtype isEqualToString:kMXMessageTypeEmote]) { + displayText = [NSString stringWithFormat:@"* %@ %@", memberDisplayName, message.content[@"body"]]; + } else if ([msgtype isEqualToString:kMXMessageTypeImage]) { + displayText = @"image attachment"; + } else if ([msgtype isEqualToString:kMXMessageTypeAudio]) { + displayText = @"audio attachment"; + } else if ([msgtype isEqualToString:kMXMessageTypeVideo]) { + displayText = @"video attachment"; + } else if ([msgtype isEqualToString:kMXMessageTypeLocation]) { + displayText = @"location attachment"; + } + + // Check whether the sender name has to be added + if (isSubtitle && [msgtype isEqualToString:kMXMessageTypeEmote] == NO) { + displayText = [NSString stringWithFormat:@"%@: %@", memberDisplayName, displayText]; + } + + break; + } + case MXEventTypeRoomMessageFeedback: { + NSString *type = message.content[@"type"]; + NSString *eventId = message.content[@"target_event_id"]; + if (type && eventId) { + displayText = [NSString stringWithFormat:@"Feedback event (id: %@): %@", eventId, type]; + } + break; + } + case MXEventTypeCustom: + break; + default: + break; + } + + if (displayText == nil) { + NSLog(@"ERROR: Unsupported message %@)", message.description); + if (isSubtitle || [AppSettings sharedSettings].hideUnsupportedMessages) { + displayText = @""; + } else { + // Return event content as unsupported message + displayText = [NSString stringWithFormat:@"%@%@", kMatrixHandlerUnsupportedMessagePrefix, message.description]; + } + } + + return displayText; +} + +@end diff --git a/matrixConsole/MediaManager.h b/matrixConsole/MediaManager.h new file mode 100644 index 000000000..82852184c --- /dev/null +++ b/matrixConsole/MediaManager.h @@ -0,0 +1,50 @@ +/* + Copyright 2014 OpenMarket 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 +#import + +extern NSString *const kMediaManagerPrefixForDummyURL; + +// The callback blocks +typedef void (^blockMediaManager_onImageReady)(UIImage *image); +typedef void (^blockMediaManager_onMediaReady)(NSString *cacheFilePath); +typedef void (^blockMediaManager_onError)(NSError *error); + +@interface MediaManager : NSObject + ++ (id)sharedInstance; + ++ (UIImage *)resize:(UIImage *)image toFitInSize:(CGSize)size; + +// Load a picture from the local cache or download it if it is not available yet. +// In this second case a mediaLoader reference is returned in order to let the user cancel this action. ++ (id)loadPicture:(NSString *)pictureURL + success:(blockMediaManager_onImageReady)success + failure:(blockMediaManager_onError)failure; +// Prepare a media from the local cache or download it if it is not available yet. +// In this second case a mediaLoader reference is returned in order to let the user cancel this action. ++ (id)prepareMedia:(NSString *)mediaURL + mimeType:(NSString *)mimeType + success:(blockMediaManager_onMediaReady)success + failure:(blockMediaManager_onError)failure; ++ (void)cancel:(id)mediaLoader; + ++ (NSString *)cacheMediaData:(NSData *)mediaData forURL:(NSString *)mediaURL mimeType:(NSString *)mimeType; + ++ (void)clearCache; + +@end diff --git a/matrixConsole/MediaManager.m b/matrixConsole/MediaManager.m new file mode 100644 index 000000000..4fb111d02 --- /dev/null +++ b/matrixConsole/MediaManager.m @@ -0,0 +1,327 @@ +/* + Copyright 2014 OpenMarket 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 "MediaManager.h" + +NSString *const kMediaManagerPrefixForDummyURL = @"dummyUrl-"; + +static NSString* mediaCachePath = nil; +static NSString *mediaDir = @"mediacache"; + +static MediaManager *sharedMediaManager = nil; + +@interface MediaLoader : NSObject { + NSString *mediaURL; + NSString *mimeType; + + blockMediaManager_onMediaReady onMediaReady; + blockMediaManager_onError onError; + + NSMutableData *downloadData; + NSURLConnection *downloadConnection; +} +@end + +#pragma mark - MediaLoader + +@implementation MediaLoader + +- (void)downloadPicture:(NSString*)pictureURL + success:(blockMediaManager_onImageReady)success + failure:(blockMediaManager_onError)failure { + // Download picture content + [self downloadMedia:pictureURL mimeType:@"image/jpeg" success:^(NSString *cacheFilePath) { + if (success) { + NSData* imageContent = [NSData dataWithContentsOfFile:cacheFilePath options:(NSDataReadingMappedAlways | NSDataReadingUncached) error:nil]; + if (imageContent) { + UIImage *image = [UIImage imageWithData:imageContent]; + if (image) { + success(image); + } else { + NSLog(@"ERROR: picture download failed: %@", pictureURL); + if (failure){ + failure(nil); + } + } + } + } + } failure:^(NSError *error) { + failure(error); + }]; +} + +- (void)downloadMedia:(NSString*)aMediaURL + mimeType:(NSString *)aMimeType + success:(blockMediaManager_onMediaReady)success + failure:(blockMediaManager_onError)failure { + // Report provided params + mediaURL = aMediaURL; + mimeType = aMimeType; + onMediaReady = success; + onError = failure; + + // Start downloading + NSURL *url = [NSURL URLWithString:aMediaURL]; + downloadData = [[NSMutableData alloc] init]; + downloadConnection = [[NSURLConnection alloc] initWithRequest:[NSURLRequest requestWithURL:url] delegate:self]; +} + +- (void)cancel { + // Reset blocks + onMediaReady = nil; + onError = nil; + // Cancel potential connection + if (downloadConnection) { + [downloadConnection cancel]; + downloadConnection = nil; + downloadData = nil; + } +} + +- (void)dealloc { + [self cancel]; +} + +#pragma mark - + +- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { + NSLog(@"ERROR: media download failed: %@, %@", error, mediaURL); + if (onError) { + onError (error); + } +} + +- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { + // Append data + [downloadData appendData:data]; +} + +- (void)connectionDidFinishLoading:(NSURLConnection *)connection { + if (downloadData.length) { + // Cache the downloaded data + NSString *cacheFilePath = [MediaManager cacheMediaData:downloadData forURL:mediaURL mimeType:mimeType]; + // Call registered block + if (onMediaReady) { + onMediaReady(cacheFilePath); + } + } else { + NSLog(@"ERROR: media download failed: %@", mediaURL); + if (onError){ + onError(nil); + } + } + + downloadData = nil; + downloadConnection = nil; +} + +@end + +#pragma mark - MediaManager + +@implementation MediaManager + ++ (id)sharedInstance { + @synchronized(self) { + if(sharedMediaManager == nil) + sharedMediaManager = [[self alloc] init]; + } + return sharedMediaManager; +} + ++ (UIImage *)resize:(UIImage *)image toFitInSize:(CGSize)size { + UIImage *resizedImage = image; + + // Check whether resize is required + if (size.width && size.height) { + CGFloat width = image.size.width; + CGFloat height = image.size.height; + + if (width > size.width) { + height = (height * size.width) / width; + height = floorf(height / 2) * 2; + width = size.width; + } + if (height > size.height) { + width = (width * size.height) / height; + width = floorf(width / 2) * 2; + height = size.height; + } + + if (width != image.size.width || height != image.size.height) { + // Create the thumbnail + CGSize imageSize = CGSizeMake(width, height); + UIGraphicsBeginImageContext(imageSize); + + CGRect thumbnailRect = CGRectMake(0, 0, 0, 0); + thumbnailRect.origin = CGPointMake(0.0,0.0); + thumbnailRect.size.width = imageSize.width; + thumbnailRect.size.height = imageSize.height; + + [image drawInRect:thumbnailRect]; + resizedImage = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + } + } + + return resizedImage; +} + +// Load a picture from the local cache or download it if it is not available yet. +// In this second case a mediaLoader reference is returned in order to let the user cancel this action. ++ (id)loadPicture:(NSString*)pictureURL + success:(blockMediaManager_onImageReady)success + failure:(blockMediaManager_onError)failure { + id ret = nil; + // Check cached pictures + UIImage *image = [MediaManager loadCachePicture:pictureURL]; + if (image) { + if (success) { + // Reply synchronously + success (image); + } + } + else if ([pictureURL hasPrefix:kMediaManagerPrefixForDummyURL] == NO) { + // Create a media loader to download picture + MediaLoader *mediaLoader = [[MediaLoader alloc] init]; + [mediaLoader downloadPicture:pictureURL success:success failure:failure]; + ret = mediaLoader; + } else { + NSLog(@"Load tmp picture from cache failed: %@", pictureURL); + if (failure){ + failure(nil); + } + } + return ret; +} + ++ (id)prepareMedia:(NSString *)mediaURL + mimeType:(NSString *)mimeType + success:(blockMediaManager_onMediaReady)success + failure:(blockMediaManager_onError)failure { + id ret = nil; + // Check cache + NSString* filename = [MediaManager getCacheFileNameFor:mediaURL mimeType:mimeType]; + if ([[NSFileManager defaultManager] fileExistsAtPath:filename]) { + if (success) { + // Reply synchronously + success (filename); + } + } + else if ([mediaURL hasPrefix:kMediaManagerPrefixForDummyURL] == NO) { + // Create a media loader to download media content + MediaLoader *mediaLoader = [[MediaLoader alloc] init]; + [mediaLoader downloadMedia:mediaURL mimeType:mimeType success:success failure:failure]; + ret = mediaLoader; + } else { + NSLog(@"Load tmp media from cache failed: %@", mediaURL); + if (failure){ + failure(nil); + } + } + return ret; +} + ++ (void)cancel:(id)mediaLoader { + [((MediaLoader*)mediaLoader) cancel]; +} + ++ (NSString*)cacheMediaData:(NSData*)mediaData forURL:(NSString *)mediaURL mimeType:(NSString *)mimeType { + NSString* filename = [MediaManager getCacheFileNameFor:mediaURL mimeType:mimeType]; + + if ([mediaData writeToFile:filename atomically:YES]) { + return filename; + } else { + return nil; + } +} + ++ (void)clearCache { + NSError *error = nil; + + if (!mediaCachePath) { + // compute the path + mediaCachePath = [MediaManager getCachePath]; + } + + if (mediaCachePath) { + if (![[NSFileManager defaultManager] removeItemAtPath:mediaCachePath error:&error]) { + NSLog(@"Fails to delete media cache dir : %@", error); + } else { + NSLog(@"Media cache : deleted !"); + } + } else { + NSLog(@"Media cache does not exist"); + } + + mediaCachePath = nil; +} + +#pragma mark - Cache handling + ++ (UIImage*)loadCachePicture:(NSString*)pictureURL { + UIImage* res = nil; + NSString* filename = [MediaManager getCacheFileNameFor:pictureURL mimeType:@"image/jpeg"]; + + if ([[NSFileManager defaultManager] fileExistsAtPath:filename]) { + NSData* imageContent = [NSData dataWithContentsOfFile:filename options:(NSDataReadingMappedAlways | NSDataReadingUncached) error:nil]; + if (imageContent) { + res = [[UIImage alloc] initWithData:imageContent]; + } + } + + return res; +} + ++ (NSString*)getCachePath { + NSString *cachePath = nil; + + if (!mediaCachePath) { + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); + NSString *cacheRoot = [paths objectAtIndex:0]; + + mediaCachePath = [cacheRoot stringByAppendingPathComponent:mediaDir]; + + if (![[NSFileManager defaultManager] fileExistsAtPath:mediaCachePath]) { + [[NSFileManager defaultManager] createDirectoryAtPath:mediaCachePath withIntermediateDirectories:NO attributes:nil error:nil]; + } + } + cachePath = mediaCachePath; + + return cachePath; +} + ++ (NSString*)getCacheFileNameFor:(NSString*)mediaURL mimeType:(NSString *)mimeType { + NSString *fileName; + if ([mimeType isEqualToString:@"image/jpeg"]) { + fileName = [NSString stringWithFormat:@"ima%lu.jpg", (unsigned long)mediaURL.hash]; + } else if ([mimeType isEqualToString:@"video/mp4"]) { + fileName = [NSString stringWithFormat:@"video%lu.mp4", (unsigned long)mediaURL.hash]; + } else if ([mimeType isEqualToString:@"video/quicktime"]) { + fileName = [NSString stringWithFormat:@"video%lu.mov", (unsigned long)mediaURL.hash]; + } else { + NSString *extension = @""; + NSArray *components = [mediaURL componentsSeparatedByString:@"."]; + if (components && components.count > 1) { + extension = [components lastObject]; + } + fileName = [NSString stringWithFormat:@"%lu.%@", (unsigned long)mediaURL.hash, extension]; + } + + return [[MediaManager getCachePath] stringByAppendingPathComponent:fileName]; +} + +@end diff --git a/matrixConsole/View/CustomImageView.h b/matrixConsole/View/CustomImageView.h new file mode 100644 index 000000000..9095727d5 --- /dev/null +++ b/matrixConsole/View/CustomImageView.h @@ -0,0 +1,27 @@ +/* + Copyright 2014 OpenMarket 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 + +// Customize UIImageView in order to let UIImageView handle automatically remote url +@interface CustomImageView : UIImageView + +@property (strong, nonatomic) NSString *placeholder; +@property (strong, nonatomic) NSString *imageURL; +// Information about the media represented by this image (image, video...) +@property (strong, nonatomic) NSDictionary *mediaInfo; +@end + diff --git a/matrixConsole/View/CustomImageView.m b/matrixConsole/View/CustomImageView.m new file mode 100644 index 000000000..c231e8137 --- /dev/null +++ b/matrixConsole/View/CustomImageView.m @@ -0,0 +1,82 @@ +/* + Copyright 2014 OpenMarket 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 "CustomImageView.h" +#import "MediaManager.h" + +@interface CustomImageView () { + id imageLoader; + UIActivityIndicatorView *loadingWheel; +} +@end + +@implementation CustomImageView + +- (void)setImageURL:(NSString *)imageURL { + // Cancel media loader in progress (if any) + if (imageLoader) { + [MediaManager cancel:imageLoader]; + imageLoader = nil; + } + + _imageURL = imageURL; + + // Reset image view + self.image = nil; + if (_placeholder) { + // Set picture placeholder + self.image = [UIImage imageNamed:_placeholder]; + } + // Consider provided url to update image view + if (imageURL) { + // Start loading animation + if (loadingWheel == nil) { + loadingWheel = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]; + CGPoint center = CGPointMake(self.frame.size.width / 2, self.frame.size.height / 2); + loadingWheel.center = center; + [self addSubview:loadingWheel]; + } + if ([self.backgroundColor isEqual:[UIColor blackColor]]) { + loadingWheel.activityIndicatorViewStyle = UIActivityIndicatorViewStyleWhite; + } else { + loadingWheel.activityIndicatorViewStyle = UIActivityIndicatorViewStyleGray; + } + [loadingWheel startAnimating]; + // Load picture + imageLoader = [MediaManager loadPicture:imageURL + success:^(UIImage *image) { + [loadingWheel stopAnimating]; + self.image = image; + } + failure:^(NSError *error) { + [loadingWheel stopAnimating]; + NSLog(@"Failed to download image (%@): %@", imageURL, error); + }]; + } +} + +- (void)dealloc { + if (imageLoader) { + [MediaManager cancel:imageLoader]; + imageLoader = nil; + } + if (loadingWheel) { + [loadingWheel removeFromSuperview]; + loadingWheel = nil; + } +} + +@end \ No newline at end of file diff --git a/matrixConsole/View/RecentsTableViewCell.h b/matrixConsole/View/RecentsTableViewCell.h new file mode 100644 index 000000000..27918556f --- /dev/null +++ b/matrixConsole/View/RecentsTableViewCell.h @@ -0,0 +1,25 @@ +/* + Copyright 2014 OpenMarket 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 + +@interface RecentsTableViewCell : UITableViewCell + +@property (weak, nonatomic) IBOutlet UILabel *roomTitle; +@property (weak, nonatomic) IBOutlet UILabel *lastEventDescription; +@property (weak, nonatomic) IBOutlet UILabel *recentDate; + +@end \ No newline at end of file diff --git a/matrixConsole/View/RecentsTableViewCell.m b/matrixConsole/View/RecentsTableViewCell.m new file mode 100644 index 000000000..e8d06d207 --- /dev/null +++ b/matrixConsole/View/RecentsTableViewCell.m @@ -0,0 +1,20 @@ +/* + Copyright 2014 OpenMarket 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 "RecentsTableViewCell.h" + +@implementation RecentsTableViewCell +@end \ No newline at end of file diff --git a/matrixConsole/View/RoomMemberTableCell.h b/matrixConsole/View/RoomMemberTableCell.h new file mode 100644 index 000000000..cda9dac6c --- /dev/null +++ b/matrixConsole/View/RoomMemberTableCell.h @@ -0,0 +1,32 @@ +/* + Copyright 2014 OpenMarket 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 +#import "CustomImageView.h" + +@class MXRoomMember; +@class MXRoom; + +// Room Member Table View Cell +@interface RoomMemberTableCell : UITableViewCell +@property (strong, nonatomic) IBOutlet CustomImageView *pictureView; +@property (weak, nonatomic) IBOutlet UILabel *userLabel; +@property (weak, nonatomic) IBOutlet UIProgressView *userPowerLevel; +@property (weak, nonatomic) IBOutlet UILabel *lastActiveAgoLabel; + +- (void)setRoomMember:(MXRoomMember *)roomMember withRoom:(MXRoom *)room; +@end + diff --git a/matrixConsole/View/RoomMemberTableCell.m b/matrixConsole/View/RoomMemberTableCell.m new file mode 100644 index 000000000..6cbcdfafa --- /dev/null +++ b/matrixConsole/View/RoomMemberTableCell.m @@ -0,0 +1,148 @@ +/* + Copyright 2014 OpenMarket 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 "RoomMemberTableCell.h" +#import "MatrixHandler.h" + +@implementation RoomMemberTableCell + +- (void)setRoomMember:(MXRoomMember *)roomMember withRoom:(MXRoom *)room { + if (room && roomMember) { + self.userLabel.text = [room.state memberName:roomMember.userId]; + self.pictureView.placeholder = @"default-profile"; + self.pictureView.imageURL = roomMember.avatarUrl; + // Round image view + [self.pictureView.layer setCornerRadius:self.pictureView.frame.size.width / 2]; + self.pictureView.clipsToBounds = YES; + + // Shade invited users + if (roomMember.membership == MXMembershipInvite) { + for (UIView *view in self.subviews) { + view.alpha = 0.3; + } + } else { + for (UIView *view in self.subviews) { + view.alpha = 1; + } + } + + // Customize banned and left (kicked) members + if (roomMember.membership == MXMembershipLeave || roomMember.membership == MXMembershipBan) { + self.backgroundColor = [UIColor colorWithRed:0.8 green:0.8 blue:0.8 alpha:1.0]; + + self.userPowerLevel.hidden = YES; + + self.lastActiveAgoLabel.backgroundColor = [UIColor lightGrayColor]; + self.lastActiveAgoLabel.text = (roomMember.membership == MXMembershipLeave) ? @"left" : @"banned"; + } else { + self.backgroundColor = [UIColor whiteColor]; + + // Handle power level display + self.userPowerLevel.hidden = NO; + NSDictionary *powerLevels; + if (room.state.powerLevels[@"users"]){ + // In Matrix 0.5, users power levels are listed under the `users` dictionnary + powerLevels = room.state.powerLevels[@"users"]; + } + else { + // @TODO: Remove this backward compatibility + powerLevels = room.state.powerLevels; + } + + if (powerLevels) { + int maxLevel = 0; + for (NSString *powerLevel in powerLevels.allValues) { + int level = [powerLevel intValue]; + if (level > maxLevel) { + maxLevel = level; + } + } + NSString *userPowerLevel = [powerLevels objectForKey:roomMember.userId]; // CAUTION: we invoke objectForKey here because user_id starts with an '@' character + if (userPowerLevel == nil) { + userPowerLevel = [powerLevels valueForKey:@"default"]; + } + float userPowerLevelFloat = 0.0; + if (userPowerLevel) { + userPowerLevelFloat = [userPowerLevel floatValue]; + } + self.userPowerLevel.progress = maxLevel ? userPowerLevelFloat / maxLevel : 1; + } else { + self.userPowerLevel.progress = 0; + } + + if (roomMember.membership == MXMembershipInvite) { + self.lastActiveAgoLabel.backgroundColor = [UIColor lightGrayColor]; + self.lastActiveAgoLabel.text = @"invited"; + } else { + // Get the user that corresponds to this member + MatrixHandler *mxHandler = [MatrixHandler sharedHandler]; + MXUser *user = [mxHandler.mxSession user:roomMember.userId]; + + // Prepare last active ago string + NSUInteger lastActiveAgoInSec = user.lastActiveAgo / 1000; + NSString *lastActive; + if (lastActiveAgoInSec < 60) { + lastActive = [NSString stringWithFormat:@"%ds ago", lastActiveAgoInSec]; + } else if (lastActiveAgoInSec < 3600) { + lastActive = [NSString stringWithFormat:@"%dm ago", (lastActiveAgoInSec / 60)]; + } else if (lastActiveAgoInSec < 86400) { + lastActive = [NSString stringWithFormat:@"%dh ago", (lastActiveAgoInSec / 3600)]; + } else { + lastActive = [NSString stringWithFormat:@"%dd ago", (lastActiveAgoInSec / 86400)]; + } + + // Check presence + switch (user.presence) { + case MXPresenceUnknown: { + self.lastActiveAgoLabel.backgroundColor = [UIColor clearColor]; + self.lastActiveAgoLabel.text = nil;//@"unknown"; + break; + } + case MXPresenceOnline: { + self.lastActiveAgoLabel.backgroundColor = [UIColor colorWithRed:0.2 green:0.9 blue:0.2 alpha:1.0]; + self.lastActiveAgoLabel.text = lastActive; + self.lastActiveAgoLabel.numberOfLines = 0; + break; + } + case MXPresenceUnavailable: { + self.lastActiveAgoLabel.backgroundColor = [UIColor colorWithRed:0.9 green:0.9 blue:0.0 alpha:1.0]; + self.lastActiveAgoLabel.text = lastActive; + self.lastActiveAgoLabel.numberOfLines = 0; + break; + } + case MXPresenceOffline: { + self.lastActiveAgoLabel.backgroundColor = [UIColor colorWithRed:0.9 green:0.2 blue:0.2 alpha:1.0]; + self.lastActiveAgoLabel.text = @"offline"; + break; + } + case MXPresenceFreeForChat: { + self.lastActiveAgoLabel.backgroundColor = [UIColor clearColor]; + self.lastActiveAgoLabel.text = nil;//@"free for chat"; + break; + } + case MXPresenceHidden: { + self.lastActiveAgoLabel.backgroundColor = [UIColor clearColor]; + self.lastActiveAgoLabel.text = nil;//@"hidden"; + break; + } + default: + break; + } + } + } + } +} +@end \ No newline at end of file diff --git a/matrixConsole/View/RoomMessageTableCell.h b/matrixConsole/View/RoomMessageTableCell.h new file mode 100644 index 000000000..577fb8075 --- /dev/null +++ b/matrixConsole/View/RoomMessageTableCell.h @@ -0,0 +1,44 @@ +/* + Copyright 2014 OpenMarket 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 +#import "CustomImageView.h" + +// Room Message Table View Cell +@interface RoomMessageTableCell : UITableViewCell +@property (strong, nonatomic) IBOutlet CustomImageView *pictureView; +@property (weak, nonatomic) IBOutlet UITextView *messageTextView; +@property (strong, nonatomic) IBOutlet CustomImageView *attachmentView; +@property (strong, nonatomic) IBOutlet UIImageView *playIconView; +@property (weak, nonatomic) IBOutlet UILabel *dateTimeLabel; +@property (weak, nonatomic) IBOutlet NSLayoutConstraint *msgTextViewWidthConstraint; +@property (weak, nonatomic) IBOutlet NSLayoutConstraint *msgTextViewTopConstraint; +@property (weak, nonatomic) IBOutlet NSLayoutConstraint *msgTextViewBottomConstraint; +@property (weak, nonatomic) IBOutlet NSLayoutConstraint *dateTimeLabelTopConstraint; +@property (weak, nonatomic) IBOutlet NSLayoutConstraint *attachmentViewTopAlignmentConstraint; +@property (weak, nonatomic) IBOutlet NSLayoutConstraint *attachmentViewBottomAlignmentConstraint; +@end + +@interface IncomingMessageTableCell : RoomMessageTableCell +@property (weak, nonatomic) IBOutlet UILabel *userNameLabel; +@end + +@interface OutgoingMessageTableCell : RoomMessageTableCell +@property (weak, nonatomic) IBOutlet UILabel *unsentLabel; +@property (weak, nonatomic) IBOutlet UIActivityIndicatorView *activityIndicator; +@property (weak, nonatomic) IBOutlet NSLayoutConstraint *unsentLabelTopConstraint; +@end + diff --git a/matrixConsole/View/RoomMessageTableCell.m b/matrixConsole/View/RoomMessageTableCell.m new file mode 100644 index 000000000..733ef1306 --- /dev/null +++ b/matrixConsole/View/RoomMessageTableCell.m @@ -0,0 +1,29 @@ +/* + Copyright 2014 OpenMarket 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 "RoomMessageTableCell.h" +#import "MediaManager.h" + +@implementation RoomMessageTableCell +@end + + +@implementation IncomingMessageTableCell +@end + + +@implementation OutgoingMessageTableCell +@end \ No newline at end of file diff --git a/matrixConsole/View/SettingsTableViewCell.h b/matrixConsole/View/SettingsTableViewCell.h new file mode 100644 index 000000000..51f61299a --- /dev/null +++ b/matrixConsole/View/SettingsTableViewCell.h @@ -0,0 +1,29 @@ +/* + Copyright 2014 OpenMarket 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 + +@interface SettingsTableViewCell : UITableViewCell +@end + +@interface SettingsTableCellWithSwitch : SettingsTableViewCell +@property (strong, nonatomic) IBOutlet UILabel *settingLabel; +@property (strong, nonatomic) IBOutlet UISwitch *settingSwitch; +@end + +@interface SettingsTableCellWithTextView : SettingsTableViewCell +@property (strong, nonatomic) IBOutlet UITextView *settingTextView; +@end \ No newline at end of file diff --git a/matrixConsole/View/SettingsTableViewCell.m b/matrixConsole/View/SettingsTableViewCell.m new file mode 100644 index 000000000..74f11fba5 --- /dev/null +++ b/matrixConsole/View/SettingsTableViewCell.m @@ -0,0 +1,26 @@ +/* + Copyright 2014 OpenMarket 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 "SettingsTableViewCell.h" + +@implementation SettingsTableViewCell +@end + +@implementation SettingsTableCellWithSwitch +@end + +@implementation SettingsTableCellWithTextView +@end \ No newline at end of file diff --git a/matrixConsole/ViewController/HomeViewController.h b/matrixConsole/ViewController/HomeViewController.h new file mode 100644 index 000000000..de6fde18d --- /dev/null +++ b/matrixConsole/ViewController/HomeViewController.h @@ -0,0 +1,22 @@ +/* + Copyright 2014 OpenMarket 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 + +@interface HomeViewController : UITableViewController + +@end + diff --git a/matrixConsole/ViewController/HomeViewController.m b/matrixConsole/ViewController/HomeViewController.m new file mode 100644 index 000000000..b0796bf98 --- /dev/null +++ b/matrixConsole/ViewController/HomeViewController.m @@ -0,0 +1,386 @@ +/* + Copyright 2014 OpenMarket 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 "HomeViewController.h" + +#import "MatrixHandler.h" +#import "AppDelegate.h" + + + +@interface HomeViewController () { + NSArray *publicRooms; + // List of public room names to highlight in displayed list + NSArray* highlightedPublicRooms; +} + +@property (weak, nonatomic) IBOutlet UITableView *publicRoomsTable; +@property (weak, nonatomic) IBOutlet UILabel *roomCreationLabel; +@property (weak, nonatomic) IBOutlet UILabel *roomNameLabel; +@property (weak, nonatomic) IBOutlet UILabel *roomAliasLabel; +@property (weak, nonatomic) IBOutlet UILabel *participantsLabel; +@property (weak, nonatomic) IBOutlet UITextField *roomNameTextField; +@property (weak, nonatomic) IBOutlet UITextField *roomAliasTextField; +@property (weak, nonatomic) IBOutlet UITextField *participantsTextField; +@property (weak, nonatomic) IBOutlet UISegmentedControl *roomVisibilityControl; +@property (weak, nonatomic) IBOutlet UIButton *createRoomBtn; +- (IBAction)onButtonPressed:(id)sender; + +@end + +@implementation HomeViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + // Do any additional setup after loading the view, typically from a nib. + _roomCreationLabel.backgroundColor = [UIColor colorWithRed:0.9 green:0.9 blue:0.9 alpha:1.0]; + _createRoomBtn.enabled = NO; + _createRoomBtn.alpha = 0.5; + + // Init + publicRooms = nil; + highlightedPublicRooms = @[@"#matrix:matrix.org"]; // Add here a room name to highlight its display in public room list +} + +- (void)didReceiveMemoryWarning { + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +- (void)dealloc{ + publicRooms = nil; + highlightedPublicRooms = nil; +} + +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + + // Ensure to display room creation section + [self.tableView scrollRectToVisible:_roomCreationLabel.frame animated:NO]; + + if ([[MatrixHandler sharedHandler] isLogged]) { + // Update alias placeholder + _roomAliasTextField.placeholder = [NSString stringWithFormat:@"(e.g. #foo:%@)", [MatrixHandler sharedHandler].homeServer]; + // Refresh listed public rooms + [self refreshPublicRooms]; + } + + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onTextFieldChange:) name:UITextFieldTextDidChangeNotification object:nil]; +} + +- (void)viewWillDisappear:(BOOL)animated { + [super viewWillDisappear:animated]; + + [[NSNotificationCenter defaultCenter] removeObserver:self name:UITextFieldTextDidChangeNotification object:nil]; +} + +#pragma mark - Internals + +- (void)refreshPublicRooms { + // Retrieve public rooms + [[MatrixHandler sharedHandler].mxRestClient publicRooms:^(NSArray *rooms){ + publicRooms = [rooms sortedArrayUsingComparator:^NSComparisonResult(id a, id b) { + + MXPublicRoom *firstRoom = (MXPublicRoom*)a; + MXPublicRoom *secondRoom = (MXPublicRoom*)b; + + return [firstRoom.displayname compare:secondRoom.displayname options:NSCaseInsensitiveSearch]; + }]; + [_publicRoomsTable reloadData]; + } + failure:^(NSError *error){ + NSLog(@"GET public rooms failed: %@", error); + //Alert user + [[AppDelegate theDelegate] showErrorAsAlert:error]; + }]; + +} + +- (void)dismissKeyboard { + // Hide the keyboard + [_roomNameTextField resignFirstResponder]; + [_roomAliasTextField resignFirstResponder]; + [_participantsTextField resignFirstResponder]; +} + +- (NSString*)alias { + // Extract alias name from alias text field + NSString *alias = _roomAliasTextField.text; + if (alias.length > 1) { + // Remove '#' character + alias = [alias substringFromIndex:1]; + // Remove homeserver + NSString *suffix = [NSString stringWithFormat:@":%@",[MatrixHandler sharedHandler].homeServer]; + NSRange range = [alias rangeOfString:suffix]; + alias = [alias stringByReplacingCharactersInRange:range withString:@""]; + } + + if (! alias.length) { + alias = nil; + } + + return alias; +} + +- (NSArray*)participantsList { + NSMutableArray *participants = [NSMutableArray array]; + + if (_participantsTextField.text.length) { + NSArray *components = [_participantsTextField.text componentsSeparatedByString:@";"]; + + for (NSString *component in components) { + // Remove white space from both ends + NSString *user = [component stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; + if (user.length > 1 && [user hasPrefix:@"@"]) { + [participants addObject:user]; + } + } + } + + if (participants.count == 0) { + participants = nil; + } + + return participants; +} + +#pragma mark - UITextField delegate + +- (void)onTextFieldChange:(NSNotification *)notif { + NSString *roomName = _roomNameTextField.text; + NSString *roomAlias = _roomAliasTextField.text; + NSString *participants = _participantsTextField.text; + + if (roomName.length || roomAlias.length || participants.length) { + _createRoomBtn.enabled = YES; + _createRoomBtn.alpha = 1; + } else { + _createRoomBtn.enabled = NO; + _createRoomBtn.alpha = 0.5; + } +} + +- (void)textFieldDidBeginEditing:(UITextField *)textField { + if (textField == _roomAliasTextField) { + textField.text = self.alias; + textField.placeholder = @"foo"; + } else if (textField == _participantsTextField) { + if (textField.text.length == 0) { + textField.text = @"@"; + } + } +} + +- (void)textFieldDidEndEditing:(UITextField *)textField { + if (textField == _roomAliasTextField) { + // Compute the new phone number with this string change + NSString * alias = textField.text; + if (alias.length) { + // add homeserver as suffix + textField.text = [NSString stringWithFormat:@"#%@:%@", alias, [MatrixHandler sharedHandler].homeServer]; + } + + textField.placeholder = [NSString stringWithFormat:@"(e.g. #foo:%@)", [MatrixHandler sharedHandler].homeServer]; + } else if (textField == _participantsTextField) { + NSArray *participants = self.participantsList; + textField.text = [participants componentsJoinedByString:@"; "]; + } +} + +- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { + // Auto complete participant IDs + if (textField == _participantsTextField) { + // Auto completion is active only when the change concerns the end of the current string + if (range.location == textField.text.length) { + NSString *participants = [textField.text stringByReplacingCharactersInRange:range withString:string]; + + if ([string isEqualToString:@";"]) { + // Add '@' character + participants = [participants stringByAppendingString:@" @"]; + } else if ([string isEqualToString:@":"]) { + // Add homeserver + participants = [participants stringByAppendingString:[MatrixHandler sharedHandler].homeServer]; + } + + textField.text = participants; + + // Update Create button status + [self onTextFieldChange:nil]; + return NO; + } + } + return YES; +} + +- (BOOL)textFieldShouldReturn:(UITextField*) textField { + // "Done" key has been pressed + [textField resignFirstResponder]; + return YES; +} + +#pragma mark - Actions + +- (IBAction)onButtonPressed:(id)sender { + [self dismissKeyboard]; + + if (sender == _createRoomBtn) { + // Disable button to prevent multiple request + _createRoomBtn.enabled = NO; + + NSString *roomName = _roomNameTextField.text; + if (! roomName.length) { + roomName = nil; + } + + // Create new room + MatrixHandler *mxHandler = [MatrixHandler sharedHandler]; + [mxHandler.mxRestClient createRoom:roomName + visibility:(_roomVisibilityControl.selectedSegmentIndex == 0) ? kMXRoomVisibilityPublic : kMXRoomVisibilityPrivate + room_alias_name:self.alias + topic:nil + success:^(MXCreateRoomResponse *response) { + // Check whether some users must be invited + NSArray *invitedUsers = self.participantsList; + for (NSString *userId in invitedUsers) { + [mxHandler.mxRestClient inviteUser:userId toRoom:response.roomId success:^{ + NSLog(@"%@ has been invited (roomId: %@)", userId, response.roomId); + } failure:^(NSError *error) { + NSLog(@"%@ invitation failed (roomId: %@): %@", userId, response.roomId, error); + //Alert user + [[AppDelegate theDelegate] showErrorAsAlert:error]; + }]; + } + + // Reset text fields + _roomNameTextField.text = nil; + _roomAliasTextField.text = nil; + _participantsTextField.text = nil; + // Open created room + [[AppDelegate theDelegate].masterTabBarController showRoom:response.roomId]; + } failure:^(NSError *error) { + _createRoomBtn.enabled = YES; + NSLog(@"Create room (%@ %@ (%@)) failed: %@", _roomNameTextField.text, self.alias, (_roomVisibilityControl.selectedSegmentIndex == 0) ? @"Public":@"Private", error); + //Alert user + [[AppDelegate theDelegate] showErrorAsAlert:error]; + }]; + } +} + +#pragma mark - Table view data source + +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { + return 1; +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + return publicRooms.count; +} + +- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { + UILabel *sectionHeader = [[UILabel alloc] initWithFrame:[tableView rectForHeaderInSection:section]]; + sectionHeader.font = [UIFont boldSystemFontOfSize:16]; + sectionHeader.backgroundColor = [UIColor colorWithRed:0.9 green:0.9 blue:0.9 alpha:1.0]; + + if (publicRooms) { + NSString *homeserver = [MatrixHandler sharedHandler].homeServerURL; + if (homeserver.length) { + sectionHeader.text = [NSString stringWithFormat:@" Public Rooms (at %@):", homeserver]; + } else { + sectionHeader.text = @" Public Rooms:"; + } + } else { + sectionHeader.text = @" No Public Rooms"; + } + + return sectionHeader; +} + +- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath +{ + // Cell is larger for public room with topic + MXPublicRoom *publicRoom = [publicRooms objectAtIndex:indexPath.row]; + if (publicRoom.topic) { + return 60; + } + return 44; +} + +- (UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { + MXPublicRoom *publicRoom = [publicRooms objectAtIndex:indexPath.row]; + UITableViewCell *cell; + + // Check whether this public room has topic + if (publicRoom.topic) { + cell = [_publicRoomsTable dequeueReusableCellWithIdentifier:@"PublicRoomCellSubtitle" forIndexPath:indexPath]; + cell.detailTextLabel.text = publicRoom.topic; + } else { + cell = [_publicRoomsTable dequeueReusableCellWithIdentifier:@"PublicRoomCellBasic" forIndexPath:indexPath]; + } + + // Set room display name + cell.textLabel.text = [publicRoom displayname]; + + // Highlight? + if (cell.textLabel.text && [highlightedPublicRooms indexOfObject:cell.textLabel.text] != NSNotFound) { + cell.textLabel.font = [UIFont boldSystemFontOfSize:20]; + cell.detailTextLabel.font = [UIFont boldSystemFontOfSize:17]; + } else { + cell.textLabel.font = [UIFont systemFontOfSize:19]; + cell.detailTextLabel.font = [UIFont systemFontOfSize:16]; + } + + return cell; +} + +#pragma mark - Table view delegate + +- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { + MatrixHandler *mxHandler = [MatrixHandler sharedHandler]; + + // Check whether the user has already joined the selected public room + MXPublicRoom *publicRoom = [publicRooms objectAtIndex:indexPath.row]; + if ([mxHandler.mxSession room:publicRoom.roomId]) { + // Open selected room + [[AppDelegate theDelegate].masterTabBarController showRoom:publicRoom.roomId]; + } else { + // Join the selected room + UIActivityIndicatorView *loadingWheel = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]; + UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath]; + if (selectedCell) { + CGPoint center = CGPointMake(selectedCell.frame.size.width / 2, selectedCell.frame.size.height / 2); + loadingWheel.center = center; + [selectedCell addSubview:loadingWheel]; + } + [loadingWheel startAnimating]; + [mxHandler.mxSession joinRoom:publicRoom.roomId success:^(MXRoom *room) { + // Show joined room + [loadingWheel stopAnimating]; + [loadingWheel removeFromSuperview]; + [[AppDelegate theDelegate].masterTabBarController showRoom:publicRoom.roomId]; + } failure:^(NSError *error) { + NSLog(@"Failed to join public room (%@) failed: %@", publicRoom.displayname, error); + //Alert user + [loadingWheel stopAnimating]; + [loadingWheel removeFromSuperview]; + [[AppDelegate theDelegate] showErrorAsAlert:error]; + }]; + } + + [tableView deselectRowAtIndexPath:indexPath animated:YES]; +} + +@end diff --git a/matrixConsole/ViewController/LoginViewController.h b/matrixConsole/ViewController/LoginViewController.h new file mode 100644 index 000000000..cf5b84442 --- /dev/null +++ b/matrixConsole/ViewController/LoginViewController.h @@ -0,0 +1,22 @@ +/* + Copyright 2014 OpenMarket 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 + +@interface LoginViewController : UIViewController + +@end + diff --git a/matrixConsole/ViewController/LoginViewController.m b/matrixConsole/ViewController/LoginViewController.m new file mode 100644 index 000000000..0c66336d1 --- /dev/null +++ b/matrixConsole/ViewController/LoginViewController.m @@ -0,0 +1,226 @@ +/* + Copyright 2014 OpenMarket 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 "LoginViewController.h" + +#import "MatrixHandler.h" +#import "AppDelegate.h" +#import "CustomAlert.h" + +NSString* const defaultHomeserver = @"http://matrix.org"; + +@interface LoginViewController () +@property (weak, nonatomic) IBOutlet NSLayoutConstraint *contentViewBottomConstraint; + +@property (strong, nonatomic) IBOutlet UIScrollView *scrollView; +@property (weak, nonatomic) IBOutlet UIView *contentView; + +@property (weak, nonatomic) IBOutlet UITextField *homeServerTextField; +@property (weak, nonatomic) IBOutlet UITextField *userLoginTextField; +@property (weak, nonatomic) IBOutlet UITextField *passWordTextField; + +@property (weak, nonatomic) IBOutlet UIButton *loginBtn; +@property (weak, nonatomic) IBOutlet UIButton *createAccountBtn; + +@property (strong, nonatomic) IBOutlet UIActivityIndicatorView *activityIndicator; + +@end + +@implementation LoginViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + // Do any additional setup after loading the view, typically from a nib. + + // Finalize scrollView content size + _contentViewBottomConstraint.constant = 0; + + // Force contentView in full width + NSLayoutConstraint *leftConstraint = [NSLayoutConstraint constraintWithItem:self.contentView + attribute:NSLayoutAttributeLeading + relatedBy:0 + toItem:self.view + attribute:NSLayoutAttributeLeft + multiplier:1.0 + constant:0]; + [self.view addConstraint:leftConstraint]; + + NSLayoutConstraint *rightConstraint = [NSLayoutConstraint constraintWithItem:self.contentView + attribute:NSLayoutAttributeTrailing + relatedBy:0 + toItem:self.view + attribute:NSLayoutAttributeRight + multiplier:1.0 + constant:0]; + [self.view addConstraint:rightConstraint]; + + // Prefill text field + _userLoginTextField.text = [[MatrixHandler sharedHandler] userLogin]; + _homeServerTextField.text = [[MatrixHandler sharedHandler] homeServerURL]; + if (! _homeServerTextField.text.length) { + [[MatrixHandler sharedHandler] setHomeServerURL:defaultHomeserver]; + self.homeServerTextField.text = defaultHomeserver; + } + _passWordTextField.text = nil; + _loginBtn.enabled = NO; + _loginBtn.alpha = 0.5; +} + +- (void)didReceiveMemoryWarning { + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onKeyboardWillShow:) name:UIKeyboardWillShowNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onKeyboardWillHide:) name:UIKeyboardWillHideNotification object:nil]; + + + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onTextFieldChange:) name:UITextFieldTextDidChangeNotification object:nil]; +} + +- (void)viewWillDisappear:(BOOL)animated { + [super viewWillDisappear:animated]; + + [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil]; + [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil]; + [[NSNotificationCenter defaultCenter] removeObserver:self name:UITextFieldTextDidChangeNotification object:nil]; +} + +- (void)onKeyboardWillShow:(NSNotification *)notif { + NSValue *rectVal = notif.userInfo[UIKeyboardFrameEndUserInfoKey]; + CGRect endRect = rectVal.CGRectValue; + + UIEdgeInsets insets = self.scrollView.contentInset; + // Handle portrait/landscape mode + insets.bottom = (endRect.origin.y == 0) ? endRect.size.width : endRect.size.height; + self.scrollView.contentInset = insets; + + for (UITextField *tf in @[ self.userLoginTextField, self.passWordTextField, self.homeServerTextField]) { + if ([tf isFirstResponder]) { + CGRect tfFrame = tf.frame; + [self.scrollView scrollRectToVisible:tfFrame animated:YES]; + } + } +} + +- (void)onKeyboardWillHide:(NSNotification *)notif { + UIEdgeInsets insets = self.scrollView.contentInset; + insets.bottom = 0; + self.scrollView.contentInset = insets; +} + +- (void)dismissKeyboard +{ + // Hide the keyboard + [_userLoginTextField resignFirstResponder]; + [_passWordTextField resignFirstResponder]; + [_homeServerTextField resignFirstResponder]; +} + +#pragma mark - UITextField delegate + +- (void)onTextFieldChange:(NSNotification *)notif { + NSString *user = _userLoginTextField.text; + NSString *pass = _passWordTextField.text; + NSString *homeServerURL = _homeServerTextField.text; + + if (user.length && pass.length && homeServerURL.length) { + _loginBtn.enabled = YES; + _loginBtn.alpha = 1; + } else { + _loginBtn.enabled = NO; + _loginBtn.alpha = 0.5; + } +} + +- (void)textFieldDidEndEditing:(UITextField *)textField +{ + MatrixHandler *matrix = [MatrixHandler sharedHandler]; + + if (textField == _userLoginTextField) { + [matrix setUserLogin:textField.text]; + } + else if (textField == _homeServerTextField) { + [matrix setHomeServerURL:textField.text]; + } +} + +- (BOOL)textFieldShouldReturn:(UITextField*) textField +{ + if (textField == _userLoginTextField) { + // "Next" key has been pressed + [_passWordTextField becomeFirstResponder]; + } + else { + // "Done" key has been pressed + [textField resignFirstResponder]; + + if (_loginBtn.isEnabled) + { + // Launch authentication now + [self onButtonPressed:_loginBtn]; + } + } + + return YES; +} + +#pragma mark - + +- (IBAction)onButtonPressed:(id)sender +{ + [self dismissKeyboard]; + + if (sender == _loginBtn) { + MatrixHandler *matrix = [MatrixHandler sharedHandler]; + + if (matrix.mxRestClient) + { + // Disable login button to prevent multiple requests + _loginBtn.enabled = NO; + [_activityIndicator startAnimating]; + + [matrix.mxRestClient loginWithUser:matrix.userLogin andPassword:_passWordTextField.text + success:^(MXCredentials *credentials){ + [_activityIndicator stopAnimating]; + + // Report credentials + [matrix setUserId:credentials.userId]; + [matrix setAccessToken:credentials.accessToken]; + [matrix setHomeServer:credentials.homeServer]; + + [self dismissViewControllerAnimated:YES completion:nil]; + } + failure:^(NSError *error){ + [_activityIndicator stopAnimating]; + _loginBtn.enabled = YES; + + NSLog(@"Login failed: %@", error); + //Alert user + CustomAlert *alert = [[CustomAlert alloc] initWithTitle:@"Login Failed" message:@"Invalid username/password" style:CustomAlertStyleAlert]; + [alert addActionWithTitle:@"Dismiss" style:CustomAlertActionStyleCancel handler:^(CustomAlert *alert) {}]; + [alert showInViewController:self]; + }]; + } + } else if (sender == _createAccountBtn){ + // TODO + } +} + +@end diff --git a/matrixConsole/ViewController/MasterTabBarController.h b/matrixConsole/ViewController/MasterTabBarController.h new file mode 100644 index 000000000..120b55663 --- /dev/null +++ b/matrixConsole/ViewController/MasterTabBarController.h @@ -0,0 +1,36 @@ +/* + Copyright 2014 OpenMarket 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 + +#define TABBAR_HOME_INDEX 0 +#define TABBAR_RECENTS_INDEX 1 +#define TABBAR_SETTINGS_INDEX 2 +#define TABBAR_COUNT 3 + +@interface MasterTabBarController : UITabBarController + +- (void)showLoginScreen; +- (void)showRoomCreationForm; +- (void)showRoom:(NSString*)roomId; + +- (void)presentMediaPicker:(UIImagePickerController*)mediaPicker; +- (void)dismissMediaPicker; + +@property (strong, nonatomic) NSString *visibleRoomId; // nil if no room is presently visible + +@end + diff --git a/matrixConsole/ViewController/MasterTabBarController.m b/matrixConsole/ViewController/MasterTabBarController.m new file mode 100644 index 000000000..aa9a92c81 --- /dev/null +++ b/matrixConsole/ViewController/MasterTabBarController.m @@ -0,0 +1,137 @@ +/* + Copyright 2014 OpenMarket 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 "MasterTabBarController.h" +#import "MatrixHandler.h" + +#import "RecentsViewController.h" + +@interface MasterTabBarController () { + UINavigationController *recentsNavigationController; + RecentsViewController *recentsViewController; + + UIImagePickerController *mediaPicker; +} + +@end + +@implementation MasterTabBarController + +@synthesize visibleRoomId; + +- (void)viewDidLoad { + [super viewDidLoad]; + // Do any additional setup after loading the view, typically from a nib. + + // To simplify navigation into the app, we retrieve here the navigation controller and the view controller related + // to the recents list in Recents Tab. + // Note: UISplitViewController is not supported on iPhone for iOS < 8.0 + UIViewController* recents = [self.viewControllers objectAtIndex:TABBAR_RECENTS_INDEX]; + recentsNavigationController = nil; + if ([recents isKindOfClass:[UISplitViewController class]]) { + UISplitViewController *splitViewController = (UISplitViewController *)recents; + recentsNavigationController = [splitViewController.viewControllers objectAtIndex:0]; + } else if ([recents isKindOfClass:[UINavigationController class]]) { + recentsNavigationController = (UINavigationController*)recents; + } + + if (recentsNavigationController) { + for (UIViewController *viewController in recentsNavigationController.viewControllers) { + if ([viewController isKindOfClass:[RecentsViewController class]]) { + recentsViewController = (RecentsViewController*)viewController; + } + } + } +} + +- (void)viewDidAppear:(BOOL)animated { + [super viewDidAppear:animated]; + + if (! [[MatrixHandler sharedHandler] isLogged]) { + [self showLoginScreen]; + } +} + +- (void)didReceiveMemoryWarning { + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +- (void)dealloc { + recentsNavigationController = nil; + recentsViewController = nil; + + [self dismissMediaPicker]; +} + +#pragma mark - + +- (void)restoreInitialDisplay { + // Dismiss potential media picker + if (mediaPicker) { + if (mediaPicker.delegate && [mediaPicker.delegate respondsToSelector:@selector(imagePickerControllerDidCancel:)]) { + [mediaPicker.delegate imagePickerControllerDidCancel:mediaPicker]; + } else { + [self dismissMediaPicker]; + } + } + + // Force back to recents list if room details is displayed in Recents Tab + if (recentsViewController) { + [recentsNavigationController popToViewController:recentsViewController animated:NO]; + } +} + +#pragma mark - + +- (void)showLoginScreen { + [self restoreInitialDisplay]; + + [self performSegueWithIdentifier:@"showLogin" sender:self]; +} + +- (void)showRoomCreationForm { + // Switch in Home Tab + [self setSelectedIndex:TABBAR_HOME_INDEX]; +} + +- (void)showRoom:(NSString*)roomId { + [self restoreInitialDisplay]; + + // Switch on Recents Tab + [self setSelectedIndex:TABBAR_RECENTS_INDEX]; + + // Select room to display its details (dispatch this action in order to let TabBarController end its refresh) + dispatch_async(dispatch_get_main_queue(), ^{ + recentsViewController.preSelectedRoomId = roomId; + }); +} + +- (void)presentMediaPicker:(UIImagePickerController*)aMediaPicker { + [self dismissMediaPicker]; + [self presentViewController:aMediaPicker animated:YES completion:^{ + mediaPicker = aMediaPicker; + }]; +} +- (void)dismissMediaPicker { + if (mediaPicker) { + [self dismissViewControllerAnimated:NO completion:nil]; + mediaPicker.delegate = nil; + mediaPicker = nil; + } +} + +@end diff --git a/matrixConsole/ViewController/RecentsViewController.h b/matrixConsole/ViewController/RecentsViewController.h new file mode 100644 index 000000000..aae4d01ec --- /dev/null +++ b/matrixConsole/ViewController/RecentsViewController.h @@ -0,0 +1,26 @@ +/* + Copyright 2014 OpenMarket 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 + +@class RoomViewController; + +@interface RecentsViewController : UITableViewController + +@property (strong, nonatomic) NSString *preSelectedRoomId; // set a non-nil value to this property will open room details + +@end + diff --git a/matrixConsole/ViewController/RecentsViewController.m b/matrixConsole/ViewController/RecentsViewController.m new file mode 100644 index 000000000..8e4b4e665 --- /dev/null +++ b/matrixConsole/ViewController/RecentsViewController.m @@ -0,0 +1,311 @@ +/* + Copyright 2014 OpenMarket 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 "RecentsViewController.h" +#import "RoomViewController.h" + +#import "RecentsTableViewCell.h" + +#import "AppDelegate.h" +#import "MatrixHandler.h" + +@interface RecentsViewController () { + NSMutableArray *recents; + id recentsListener; + + // Date formatter + NSDateFormatter *dateFormatter; + + RoomViewController *currentRoomViewController; +} +@property (strong, nonatomic) IBOutlet UIActivityIndicatorView *activityIndicator; + +@end + +@implementation RecentsViewController + +- (void)awakeFromNib { + [super awakeFromNib]; + if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) { + self.clearsSelectionOnViewWillAppear = NO; + self.preferredContentSize = CGSizeMake(320.0, 600.0); + } +} + +- (void)viewDidLoad { + [super viewDidLoad]; + // Do any additional setup after loading the view, typically from a nib. + self.navigationItem.leftBarButtonItem = self.editButtonItem; + + UIBarButtonItem *addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(createNewRoom:)]; + self.navigationItem.rightBarButtonItem = addButton; + + // Add activity indicator + [self.view addSubview:_activityIndicator]; + _activityIndicator.center = CGPointMake(self.view.center.x, 100); + [self.view bringSubviewToFront:_activityIndicator]; + + // Initialisation + recents = nil; + + NSString *dateFormat = @"MMM dd HH:mm"; + dateFormatter = [[NSDateFormatter alloc] init]; + [dateFormatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:[[[NSBundle mainBundle] preferredLocalizations] objectAtIndex:0]]]; + [dateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4]; + [dateFormatter setTimeStyle:NSDateFormatterNoStyle]; + [dateFormatter setDateFormat:dateFormat]; +} + +- (void)dealloc { + if (currentRoomViewController) { + currentRoomViewController.roomId = nil; + } + if (recentsListener) { + [[MatrixHandler sharedHandler].mxSession removeListener:recentsListener]; + recentsListener = nil; + } + recents = nil; + _preSelectedRoomId = nil; + + if (dateFormatter) { + dateFormatter = nil; + } +} + +- (void)didReceiveMemoryWarning { + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + + // Refresh recents table + [self configureView]; + [[MatrixHandler sharedHandler] addObserver:self forKeyPath:@"isInitialSyncDone" options:0 context:nil]; +} + +- (void)viewWillDisappear:(BOOL)animated { + [super viewWillDisappear:animated]; + + // Leave potential editing mode + [self setEditing:NO]; + + if (recentsListener) { + [[MatrixHandler sharedHandler].mxSession removeListener:recentsListener]; + recentsListener = nil; + } + + _preSelectedRoomId = nil; + [[MatrixHandler sharedHandler] removeObserver:self forKeyPath:@"isInitialSyncDone"]; +} + +#pragma mark - + +- (void)setPreSelectedRoomId:(NSString *)roomId { + _preSelectedRoomId = nil; + + if (roomId) { + // Check whether recents update is in progress + if ([_activityIndicator isAnimating]) { + // Postpone room details display + _preSelectedRoomId = roomId; + return; + } + + // Look for the room index in recents list + NSIndexPath *indexPath = nil; + for (NSUInteger index = 0; index < recents.count; index++) { + MXEvent *mxEvent = [recents objectAtIndex:index]; + if ([roomId isEqualToString:mxEvent.roomId]) { + indexPath = [NSIndexPath indexPathForRow:index inSection:0]; + break; + } + } + + if (indexPath) { + // Open details view + [self.tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionMiddle]; + UITableViewCell *recentCell = [self.tableView cellForRowAtIndexPath:indexPath]; + [self performSegueWithIdentifier:@"showDetail" sender:recentCell]; + } else { + NSLog(@"We are not able to open room (%@) because it does not appear in recents yet", roomId); + // Postpone room details display. We run activity indicator until recents are updated + _preSelectedRoomId = roomId; + // Start activity indicator + [_activityIndicator startAnimating]; + } + } +} + +#pragma mark - Internal methods + +- (void)configureView { + MatrixHandler *mxHandler = [MatrixHandler sharedHandler]; + + // Remove potential listener + if (recentsListener && mxHandler.mxSession) { + [mxHandler.mxSession removeListener:recentsListener]; + recentsListener = nil; + } + + [_activityIndicator startAnimating]; + + if ([mxHandler isInitialSyncDone] || [mxHandler isLogged] == NO) { + // Update recents + if (mxHandler.mxSession) { + recents = [NSMutableArray arrayWithArray:mxHandler.mxSession.recents]; + // Register recent listener + recentsListener = [mxHandler.mxSession listenToEventsOfTypes:mxHandler.mxSession.eventsFilterForMessages onEvent:^(MXEvent *event, MXEventDirection direction, id customObject) { + // consider only live event + if (direction == MXEventDirectionForwards) { + // Refresh the whole recents list + recents = [NSMutableArray arrayWithArray:mxHandler.mxSession.recents]; + // Reload table + [self.tableView reloadData]; + [_activityIndicator stopAnimating]; + + // Check whether a room is preselected + if (_preSelectedRoomId) { + self.preSelectedRoomId = _preSelectedRoomId; + } + } + }]; + } else { + recents = nil; + } + + // Reload table + [self.tableView reloadData]; + [_activityIndicator stopAnimating]; + + // Check whether a room is preselected + if (_preSelectedRoomId) { + self.preSelectedRoomId = _preSelectedRoomId; + } + } +} + +- (void)createNewRoom:(id)sender { + [[AppDelegate theDelegate].masterTabBarController showRoomCreationForm]; +} + +#pragma mark - KVO + +- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context +{ + if ([@"isInitialSyncDone" isEqualToString:keyPath]) + { + dispatch_async(dispatch_get_main_queue(), ^{ + [self configureView]; + }); + } +} + +#pragma mark - Segues + +- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { + if ([[segue identifier] isEqualToString:@"showDetail"]) { + NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow]; + MXEvent *mxEvent = recents[indexPath.row]; + + UIViewController *controller; + if ([[segue destinationViewController] isKindOfClass:[UINavigationController class]]) { + controller = [[segue destinationViewController] topViewController]; + } else { + controller = [segue destinationViewController]; + } + + if ([controller isKindOfClass:[RoomViewController class]]) { + if (currentRoomViewController) { + if ((currentRoomViewController != controller) || (![currentRoomViewController.roomId isEqualToString:mxEvent.roomId])) { + // Release the current one + currentRoomViewController.roomId = nil; + } + } + currentRoomViewController = (RoomViewController *)controller; + currentRoomViewController.roomId = mxEvent.roomId; + } + + controller.navigationItem.leftBarButtonItem = self.splitViewController.displayModeButtonItem; + controller.navigationItem.leftItemsSupplementBackButton = YES; + } +} + +#pragma mark - Table View + +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { + return 1; +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + return recents.count; +} + +- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath +{ + return 70; +} + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { + RecentsTableViewCell *cell = (RecentsTableViewCell*)[tableView dequeueReusableCellWithIdentifier:@"RecentsCell" forIndexPath:indexPath]; + + MXEvent *mxEvent = recents[indexPath.row]; + MatrixHandler *mxHandler = [MatrixHandler sharedHandler]; + MXRoom *mxRoom = [mxHandler.mxSession room:mxEvent.roomId]; + + cell.roomTitle.text = [mxRoom.state displayname]; + cell.lastEventDescription.text = [mxHandler displayTextFor:mxEvent inSubtitleMode:YES]; + + // Set in bold public room name + if (mxRoom.state.isPublic) { + cell.roomTitle.font = [UIFont boldSystemFontOfSize:20]; + } else { + cell.roomTitle.font = [UIFont systemFontOfSize:19]; + } + + if (mxEvent.originServerTs != kMXUndefinedTimestamp) { + NSDate *date = [NSDate dateWithTimeIntervalSince1970:mxEvent.originServerTs/1000]; + cell.recentDate.text = [dateFormatter stringFromDate:date]; + } else { + cell.recentDate.text = nil; + } + return cell; +} + +- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath { + // Return NO if you do not want the specified item to be editable. + return YES; +} + +- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { + if (editingStyle == UITableViewCellEditingStyleDelete) { + // Leave the selected room + MXEvent *mxEvent = recents[indexPath.row]; + MXRoom *mxRoom = [[MatrixHandler sharedHandler].mxSession room:mxEvent.roomId]; + [mxRoom leave:^{ + // Refresh table display + [recents removeObjectAtIndex:indexPath.row]; + [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade]; + } failure:^(NSError *error) { + NSLog(@"Failed to leave room (%@) failed: %@", mxEvent.roomId, error); + //Alert user + [[AppDelegate theDelegate] showErrorAsAlert:error]; + }]; + } +} + +@end diff --git a/matrixConsole/ViewController/RoomViewController.h b/matrixConsole/ViewController/RoomViewController.h new file mode 100644 index 000000000..b3959f5f0 --- /dev/null +++ b/matrixConsole/ViewController/RoomViewController.h @@ -0,0 +1,24 @@ +/* + Copyright 2014 OpenMarket 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 + +@interface RoomViewController : UIViewController + +@property (strong, nonatomic) NSString *roomId; + +@end + diff --git a/matrixConsole/ViewController/RoomViewController.m b/matrixConsole/ViewController/RoomViewController.m new file mode 100644 index 000000000..b57ab3029 --- /dev/null +++ b/matrixConsole/ViewController/RoomViewController.m @@ -0,0 +1,1834 @@ +/* + Copyright 2014 OpenMarket 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 + +#import + +#import "RoomViewController.h" +#import "RoomMessageTableCell.h" +#import "RoomMemberTableCell.h" + +#import "MatrixHandler.h" +#import "AppDelegate.h" +#import "AppSettings.h" + +#import "MediaManager.h" + +#define UPLOAD_FILE_SIZE 5000000 + +#define ROOM_MESSAGE_CELL_MAX_TEXTVIEW_WIDTH 200 + +#define ROOM_MESSAGE_CELL_TEXTVIEW_TOP_CONST_DEFAULT 10 +#define ROOM_MESSAGE_CELL_TEXTVIEW_TOP_CONST_IN_CHUNK (-5) +#define ROOM_MESSAGE_CELL_TEXTVIEW_EDGE_INSET_TOP_IN_CHUNK ROOM_MESSAGE_CELL_TEXTVIEW_TOP_CONST_IN_CHUNK +#define ROOM_MESSAGE_CELL_TEXTVIEW_BOTTOM_CONST_DEFAULT 0 +#define ROOM_MESSAGE_CELL_TEXTVIEW_BOTTOM_CONST_GROUPED_CELL (-5) + +#define ROOM_MESSAGE_CELL_IMAGE_MARGIN 8 + +NSString *const kCmdChangeDisplayName = @"/nick"; +NSString *const kCmdEmote = @"/me"; +NSString *const kCmdJoinRoom = @"/join"; +NSString *const kCmdKickUser = @"/kick"; +NSString *const kCmdBanUser = @"/ban"; +NSString *const kCmdUnbanUser = @"/unban"; +NSString *const kCmdSetUserPowerLevel = @"/op"; +NSString *const kCmdResetUserPowerLevel = @"/deop"; + +NSString *const kLocalEchoEventIdPrefix = @"localEcho-"; +NSString *const kFailedEventId = @"failedEventId"; + + +@interface RoomViewController () { + BOOL forceScrollToBottomOnViewDidAppear; + BOOL isJoinRequestInProgress; + + MXRoom *mxRoom; + + // Messages + NSMutableArray *messages; + id messagesListener; + NSString *mostRecentEventIdOnViewWillDisappear; + + // Back pagination + BOOL isBackPaginationInProgress; + NSUInteger backPaginationAddedItemsNb; + + // Members list + NSArray *members; + id membersListener; + + // Attachment handling + CustomImageView *highResImage; + NSString *AVAudioSessionCategory; + MPMoviePlayerController *videoPlayer; + + // Date formatter (nil if dateTimeLabel is hidden) + NSDateFormatter *dateFormatter; + + // Text view settings + NSAttributedString *initialAttributedStringForOutgoingMessage; + NSAttributedString *initialAttributedStringForIncomingMessage; + + // Cache + NSMutableArray *tmpCachedAttachments; +} + +@property (weak, nonatomic) IBOutlet UINavigationItem *roomNavItem; +@property (weak, nonatomic) IBOutlet UITextField *roomNameTextField; +@property (weak, nonatomic) IBOutlet UITableView *messagesTableView; +@property (weak, nonatomic) IBOutlet UIView *controlView; +@property (weak, nonatomic) IBOutlet UIButton *optionBtn; +@property (weak, nonatomic) IBOutlet UITextField *messageTextField; +@property (weak, nonatomic) IBOutlet UIButton *sendBtn; +@property (weak, nonatomic) IBOutlet NSLayoutConstraint *controlViewBottomConstraint; +@property (weak, nonatomic) IBOutlet UIActivityIndicatorView *activityIndicator; +@property (weak, nonatomic) IBOutlet UIView *membersView; +@property (weak, nonatomic) IBOutlet UITableView *membersTableView; + +@property (strong, nonatomic) CustomAlert *actionMenu; +@end + +@implementation RoomViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + // Do any additional setup after loading the view, typically from a nib. + forceScrollToBottomOnViewDidAppear = YES; + mostRecentEventIdOnViewWillDisappear = nil; + + UIButton *button = [UIButton buttonWithType:UIButtonTypeInfoLight]; + [button addTarget:self action:@selector(showHideRoomMembers:) forControlEvents:UIControlEventTouchUpInside]; + self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:button]; + + // Add tap detection on members view in order to hide members when the user taps outside members list + UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(hideRoomMembers)]; + [tap setNumberOfTouchesRequired:1]; + [tap setNumberOfTapsRequired:1]; + [tap setDelegate:self]; + [self.membersView addGestureRecognizer:tap]; + + _sendBtn.enabled = NO; + _sendBtn.alpha = 0.5; +} + +- (void)dealloc { + // Clear temporary cached attachments (used for local echo) + NSUInteger index = tmpCachedAttachments.count; + NSError *error = nil; + while (index--) { + if (![[NSFileManager defaultManager] removeItemAtPath:[tmpCachedAttachments objectAtIndex:index] error:&error]) { + NSLog(@"Fail to delete cached media: %@", error); + } + } + tmpCachedAttachments = nil; + + [self hideAttachmentView]; + + messages = nil; + if (messagesListener) { + [mxRoom removeListener:messagesListener]; + messagesListener = nil; + } + mxRoom = nil; + + members = nil; + if (membersListener) { + membersListener = nil; + } + + if (self.actionMenu) { + [self.actionMenu dismiss:NO]; + self.actionMenu = nil; + } + + if (dateFormatter) { + dateFormatter = nil; + } + + initialAttributedStringForOutgoingMessage = nil; + initialAttributedStringForIncomingMessage = nil; +} + +- (void)didReceiveMemoryWarning { + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + + if (isBackPaginationInProgress || isJoinRequestInProgress) { + // Busy - be sure that activity indicator is running + [_activityIndicator startAnimating]; + } + + if (mostRecentEventIdOnViewWillDisappear) { + if (messages) { + MXEvent *mxEvent = [messages lastObject]; + if ([mxEvent.eventId isEqualToString:mostRecentEventIdOnViewWillDisappear] == NO) { + // Some new events have been received for this room, scroll to bottom to focus on them + forceScrollToBottomOnViewDidAppear = YES; + } + } + mostRecentEventIdOnViewWillDisappear = nil; + } + + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onKeyboardWillShow:) name:UIKeyboardWillShowNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onKeyboardWillHide:) name:UIKeyboardWillHideNotification object:nil]; + + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onTextFieldChange:) name:UITextFieldTextDidChangeNotification object:nil]; + + // Set visible room id + [AppDelegate theDelegate].masterTabBarController.visibleRoomId = self.roomId; +} + +- (void)viewWillDisappear:(BOOL)animated { + [super viewWillDisappear:animated]; + + // hide action + if (self.actionMenu) { + [self.actionMenu dismiss:NO]; + self.actionMenu = nil; + } + + // Hide members by default + [self hideRoomMembers]; + + [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil]; + [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil]; + [[NSNotificationCenter defaultCenter] removeObserver:self name:UITextFieldTextDidChangeNotification object:nil]; + + // We store the eventID of the last known event (if any) in order to scroll to bottom when view will appear, if new events have been received + if (messages) { + MXEvent *mxEvent = [messages lastObject]; + mostRecentEventIdOnViewWillDisappear = mxEvent.eventId; + } + + // Reset visible room id + [AppDelegate theDelegate].masterTabBarController.visibleRoomId = nil; +} + +- (void)viewDidAppear:(BOOL)animated { + [super viewDidAppear:animated]; + + if (forceScrollToBottomOnViewDidAppear) { + // Scroll to the bottom + [self scrollToBottomAnimated:animated]; + forceScrollToBottomOnViewDidAppear = NO; + } +} + +#pragma mark - room ID + +- (void)setRoomId:(NSString *)roomId { + if ([self.roomId isEqualToString:roomId] == NO) { + _roomId = roomId; + // Reload room data here + [self configureView]; + } +} + +#pragma mark - UIGestureRecognizer delegate + +- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer { + if (gestureRecognizer.view == self.membersView) { + // Compute actual frame of the displayed members list + CGRect frame = self.membersTableView.frame; + if (self.membersTableView.tableFooterView.frame.origin.y < frame.size.height) { + frame.size.height = self.membersTableView.tableFooterView.frame.origin.y; + } + // gestureRecognizer should begin only if tap is outside members list + return !CGRectContainsPoint(frame, [gestureRecognizer locationInView:self.membersView]); + } + return YES; +} + +#pragma mark - Internal methods + +- (void)configureView { + // Check whether a request is in progress to join the room + if (isJoinRequestInProgress) { + // Busy - be sure that activity indicator is running + [_activityIndicator startAnimating]; + return; + } + + // Remove potential listener + if (messagesListener && mxRoom) { + [mxRoom removeListener:messagesListener]; + messagesListener = nil; + } + // The whole room history is flushed here to rebuild it from the current instant (live) + messages = nil; + // Disable room title edition + self.roomNameTextField.enabled = NO; + + // Update room data + if (self.roomId) { + MatrixHandler *mxHandler = [MatrixHandler sharedHandler]; + mxRoom = [mxHandler.mxSession room:self.roomId]; + + // Update room title + self.roomNameTextField.text = mxRoom.state.displayname; + + // Check first whether we have to join the room + if (mxRoom.state.membership == MXMembershipInvite) { + isJoinRequestInProgress = YES; + [_activityIndicator startAnimating]; + [mxRoom join:^{ + [_activityIndicator stopAnimating]; + isJoinRequestInProgress = NO; + dispatch_async(dispatch_get_main_queue(), ^{ + [self configureView]; + }); + } failure:^(NSError *error) { + [_activityIndicator stopAnimating]; + isJoinRequestInProgress = NO; + NSLog(@"Failed to join room (%@): %@", mxRoom.state.displayname, error); + //Alert user + [[AppDelegate theDelegate] showErrorAsAlert:error]; + }]; + return; + } + + // Enable room title edition + self.roomNameTextField.enabled = YES; + + messages = [NSMutableArray array]; + // Register a listener to handle messages + messagesListener = [mxRoom listenToEventsOfTypes:mxHandler.mxSession.eventsFilterForMessages onEvent:^(MXEvent *event, MXEventDirection direction, MXRoomState *roomState) { + BOOL shouldScrollToBottom = NO; + + // Handle first live events + if (direction == MXEventDirectionForwards) { + // For outgoing message, remove the temporary event + if ([event.userId isEqualToString:[MatrixHandler sharedHandler].userId]) { + NSUInteger index = messages.count; + while (index--) { + MXEvent *mxEvent = [messages objectAtIndex:index]; + if ([mxEvent.eventId isEqualToString:event.eventId]) { + [messages replaceObjectAtIndex:index withObject:event]; + NSIndexPath *indexPath = [NSIndexPath indexPathForRow:index inSection:0]; + [self.messagesTableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone]; + return; + } + } + } + // Here a new event is added + NSIndexPath *indexPath = [NSIndexPath indexPathForRow:messages.count inSection:0]; + [messages addObject:event]; + shouldScrollToBottom = (self.messagesTableView.contentOffset.y + self.messagesTableView.frame.size.height >= self.messagesTableView.contentSize.height); + + // Refresh table display (Disable animation during cells insertion to prevent flickering) + [UIView setAnimationsEnabled:NO]; + [self.messagesTableView beginUpdates]; + if (indexPath.row > 0) { + NSIndexPath *prevIndexPath = [NSIndexPath indexPathForRow:indexPath.row - 1 inSection:0]; + [self.messagesTableView reloadRowsAtIndexPaths:@[prevIndexPath] withRowAnimation:UITableViewRowAnimationNone]; + } + [self.messagesTableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone]; + [self.messagesTableView endUpdates]; + [UIView setAnimationsEnabled:YES]; + } else if (isBackPaginationInProgress && direction == MXEventDirectionBackwards) { + // Back pagination is in progress, we add an old event at the beginning of messages + [messages insertObject:event atIndex:0]; + backPaginationAddedItemsNb++; + // Display is refreshed at the end of back pagination (see onComplete block) + } + + if (shouldScrollToBottom) { + [self scrollToBottomAnimated:YES]; + } + }]; + + // Trigger a back pagination by reseting first backState to get room history from live + [mxRoom resetBackState]; + [self triggerBackPagination]; + } else { + mxRoom = nil; + // Update room title + self.roomNameTextField.text = nil; + } + + [self.messagesTableView reloadData]; +} + +- (void)scrollToBottomAnimated:(BOOL)animated { + // Scroll table view to the bottom + NSInteger rowNb = messages.count; + if (rowNb) { + [self.messagesTableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:(rowNb - 1) inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:animated]; + } +} + +- (void)triggerBackPagination { + // Check whether a back pagination is already in progress + if (isBackPaginationInProgress) { + return; + } + + if (mxRoom.canPaginate) { + [_activityIndicator startAnimating]; + isBackPaginationInProgress = YES; + backPaginationAddedItemsNb = 0; + + [mxRoom paginateBackMessages:20 complete:^{ + if (backPaginationAddedItemsNb) { + // Prepare insertion of new rows at the top of the table (compute cumulative height of added cells) + NSMutableArray *indexPaths = [NSMutableArray arrayWithCapacity:backPaginationAddedItemsNb]; + NSIndexPath *indexPath; + CGFloat verticalOffset = 0; + for (NSUInteger index = 0; index < backPaginationAddedItemsNb; index++) { + indexPath = [NSIndexPath indexPathForRow:index inSection:0]; + [indexPaths addObject:indexPath]; + verticalOffset += [self tableView:self.messagesTableView heightForRowAtIndexPath:indexPath]; + } + + // Disable animation during cells insertion to prevent flickering + [UIView setAnimationsEnabled:NO]; + // Store the current content offset + CGPoint contentOffset = self.messagesTableView.contentOffset; + [self.messagesTableView beginUpdates]; + [self.messagesTableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationNone]; + [self.messagesTableView endUpdates]; + // Enable animation again + [UIView setAnimationsEnabled:YES]; + // Fix vertical offset in order to prevent scrolling down + contentOffset.y += verticalOffset; + [self.messagesTableView setContentOffset:contentOffset animated:NO]; + [_activityIndicator stopAnimating]; + isBackPaginationInProgress = NO; + + // Move the current message at the middle of the visible area (dispatch this action in order to let table end its refresh) + indexPath = [NSIndexPath indexPathForRow:(backPaginationAddedItemsNb - 1) inSection:0]; + backPaginationAddedItemsNb = 0; + dispatch_async(dispatch_get_main_queue(), ^{ + [self.messagesTableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionMiddle animated:YES]; + }); + } else { + // Here there was no event related to the `messages` property + [_activityIndicator stopAnimating]; + isBackPaginationInProgress = NO; + // Trigger a new back pagination (if possible) + [self triggerBackPagination]; + } + } failure:^(NSError *error) { + [_activityIndicator stopAnimating]; + isBackPaginationInProgress = NO; + backPaginationAddedItemsNb = 0; + NSLog(@"Failed to paginate back: %@", error); + //Alert user + [[AppDelegate theDelegate] showErrorAsAlert:error]; + }]; + } +} + +# pragma mark - Room members + +- (void)showHideRoomMembers:(id)sender { + // Check whether the members list is displayed + if (members) { + [self hideRoomMembers]; + } else { + [self hideAttachmentView]; + [self showRoomMembers]; + } +} + +- (void)updateRoomMembers { + members = [[mxRoom.state members] sortedArrayUsingComparator:^NSComparisonResult(MXRoomMember *member1, MXRoomMember *member2) { + // Move banned and left members at the end of the list + if (member1.membership == MXMembershipLeave || member1.membership == MXMembershipBan) { + if (member2.membership != MXMembershipLeave && member2.membership != MXMembershipBan) { + return NSOrderedDescending; + } + } else if (member2.membership == MXMembershipLeave || member2.membership == MXMembershipBan) { + return NSOrderedAscending; + } + + // Move invited members just before left and banned members + if (member1.membership == MXMembershipInvite) { + if (member2.membership != MXMembershipInvite) { + return NSOrderedDescending; + } + } else if (member2.membership == MXMembershipInvite) { + return NSOrderedAscending; + } + + if ([[AppSettings sharedSettings] sortMembersUsingLastSeenTime]) { + // Get the users that correspond to these members + MatrixHandler *mxHandler = [MatrixHandler sharedHandler]; + MXUser *user1 = [mxHandler.mxSession user:member1.userId]; + MXUser *user2 = [mxHandler.mxSession user:member2.userId]; + + // Move users who are not online or unavailable at the end (before invited users) + if ((user1.presence == MXPresenceOnline) || (user1.presence == MXPresenceUnavailable)) { + if ((user2.presence != MXPresenceOnline) && (user2.presence != MXPresenceUnavailable)) { + return NSOrderedAscending; + } + } else if ((user2.presence == MXPresenceOnline) || (user2.presence == MXPresenceUnavailable)) { + return NSOrderedDescending; + } else { + // Here both users are neither online nor unavailable (the lastActive ago is useless) + // We will sort them according to their display, by keeping in front the offline users + if (user1.presence == MXPresenceOffline) { + if (user2.presence != MXPresenceOffline) { + return NSOrderedAscending; + } + } else if (user2.presence == MXPresenceOffline) { + return NSOrderedDescending; + } + return [[mxRoom.state memberName:member1.userId] compare:[mxRoom.state memberName:member2.userId] options:NSCaseInsensitiveSearch]; + } + + // Consider user's lastActive ago value + if (user1.lastActiveAgo < user2.lastActiveAgo) { + return NSOrderedAscending; + } else if (user1.lastActiveAgo == user2.lastActiveAgo) { + return [[mxRoom.state memberName:member1.userId] compare:[mxRoom.state memberName:member2.userId] options:NSCaseInsensitiveSearch]; + } + return NSOrderedDescending; + } else { + // Move user without display name at the end (before invited users) + if (member1.displayname.length) { + if (!member2.displayname.length) { + return NSOrderedAscending; + } + } else if (member2.displayname.length) { + return NSOrderedDescending; + } + + return [[mxRoom.state memberName:member1.userId] compare:[mxRoom.state memberName:member2.userId] options:NSCaseInsensitiveSearch]; + } + }]; +} + +- (void)showRoomMembers { + // Dismiss keyboard + [self dismissKeyboard]; + + [self updateRoomMembers]; + // Register a listener for events that concern room members + MatrixHandler *mxHandler = [MatrixHandler sharedHandler]; + NSArray *mxMembersEvents = @[ + kMXEventTypeStringRoomMember, + kMXEventTypeStringRoomPowerLevels, + kMXEventTypeStringPresence + ]; + membersListener = [mxHandler.mxSession listenToEventsOfTypes:mxMembersEvents onEvent:^(MXEvent *event, MXEventDirection direction, id customObject) { + // consider only live event + if (direction == MXEventDirectionForwards) { + // Check the room Id (if any) + if (event.roomId && [event.roomId isEqualToString:self.roomId] == NO) { + // This event does not concern the current room members + return; + } + + // Hide potential action sheet + if (self.actionMenu) { + [self.actionMenu dismiss:NO]; + self.actionMenu = nil; + } + // Refresh members list + [self updateRoomMembers]; + [self.membersTableView reloadData]; + } + }]; + + self.membersView.hidden = NO; + [self.membersTableView reloadData]; +} + +- (void)hideRoomMembers { + if (membersListener) { + MatrixHandler *mxHandler = [MatrixHandler sharedHandler]; + [mxHandler.mxSession removeListener:membersListener]; + membersListener = nil; + } + self.membersView.hidden = YES; + members = nil; +} + +# pragma mark - Attachment handling + +- (void)showAttachmentView:(UIGestureRecognizer *)gestureRecognizer { + CustomImageView *attachment = (CustomImageView*)gestureRecognizer.view; + [self dismissKeyboard]; + + // Retrieve attachment information + NSDictionary *content = attachment.mediaInfo; + NSString *msgtype = content[@"msgtype"]; + if ([msgtype isEqualToString:kMXMessageTypeImage]) { + NSString *url =content[@"url"]; + if (url.length) { + highResImage = [[CustomImageView alloc] initWithFrame:self.membersView.frame]; + highResImage.contentMode = UIViewContentModeScaleAspectFit; + highResImage.backgroundColor = [UIColor blackColor]; + highResImage.imageURL = url; + [self.view addSubview:highResImage]; + + // Add tap recognizer to hide attachment + UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(hideAttachmentView)]; + [tap setNumberOfTouchesRequired:1]; + [tap setNumberOfTapsRequired:1]; + [highResImage addGestureRecognizer:tap]; + highResImage.userInteractionEnabled = YES; + } + } else if ([msgtype isEqualToString:kMXMessageTypeVideo]) { + NSString *url =content[@"url"]; + if (url.length) { + NSString *mimetype = nil; + if (content[@"info"]) { + mimetype = content[@"info"][@"mimetype"]; + } + AVAudioSessionCategory = [[AVAudioSession sharedInstance] category]; + [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil]; + videoPlayer = [[MPMoviePlayerController alloc] init]; + if (videoPlayer != nil) { + videoPlayer.scalingMode = MPMovieScalingModeAspectFit; + [self.view addSubview:videoPlayer.view]; + [videoPlayer setFullscreen:YES animated:NO]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(moviePlayerPlaybackDidFinishNotification:) + name:MPMoviePlayerPlaybackDidFinishNotification + object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(moviePlayerWillExitFullscreen:) + name:MPMoviePlayerWillExitFullscreenNotification + object:videoPlayer]; + [MediaManager prepareMedia:url mimeType:mimetype success:^(NSString *cacheFilePath) { + if (cacheFilePath) { + if (tmpCachedAttachments == nil) { + tmpCachedAttachments = [NSMutableArray array]; + } + if ([tmpCachedAttachments indexOfObject:cacheFilePath]) { + [tmpCachedAttachments addObject:cacheFilePath]; + } + } + videoPlayer.contentURL = [NSURL fileURLWithPath:cacheFilePath]; + [videoPlayer play]; + } failure:^(NSError *error) { + [self hideAttachmentView]; + //Alert user + [[AppDelegate theDelegate] showErrorAsAlert:error]; + }]; + } + } + } else if ([msgtype isEqualToString:kMXMessageTypeAudio]) { + } else if ([msgtype isEqualToString:kMXMessageTypeLocation]) { + } +} + +- (void)hideAttachmentView { + [[NSNotificationCenter defaultCenter] removeObserver:self name:MPMoviePlayerPlaybackDidFinishNotification object:nil]; + [[NSNotificationCenter defaultCenter] removeObserver:self name:MPMoviePlayerWillExitFullscreenNotification object:nil]; + + if (highResImage) { + [highResImage removeFromSuperview]; + highResImage = nil; + } + // Restore audio category + if (AVAudioSessionCategory) { + [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategory error:nil]; + } + if (videoPlayer) { + [videoPlayer stop]; + [videoPlayer setFullscreen:NO]; + [videoPlayer.view removeFromSuperview]; + videoPlayer = nil; + } +} + +- (void)moviePlayerWillExitFullscreen:(NSNotification*)notification { + if (notification.object == videoPlayer) { + [self hideAttachmentView]; + } +} + +- (void)moviePlayerPlaybackDidFinishNotification:(NSNotification *)notification { + NSDictionary *notificationUserInfo = [notification userInfo]; + NSNumber *resultValue = [notificationUserInfo objectForKey:MPMoviePlayerPlaybackDidFinishReasonUserInfoKey]; + MPMovieFinishReason reason = [resultValue intValue]; + + // error cases + if (reason == MPMovieFinishReasonPlaybackError) { + NSError *mediaPlayerError = [notificationUserInfo objectForKey:@"error"]; + if (mediaPlayerError) { + NSLog(@"Playback failed with error description: %@", [mediaPlayerError localizedDescription]); + [self hideAttachmentView]; + //Alert user + [[AppDelegate theDelegate] showErrorAsAlert:mediaPlayerError]; + } + } +} + +#pragma mark - Keyboard handling + +- (void)onKeyboardWillShow:(NSNotification *)notif { + NSValue *rectVal = notif.userInfo[UIKeyboardFrameEndUserInfoKey]; + CGRect endRect = rectVal.CGRectValue; + + UIEdgeInsets insets = self.messagesTableView.contentInset; + // Handle portrait/landscape mode + insets.bottom = (endRect.origin.y == 0) ? endRect.size.width : endRect.size.height; + self.messagesTableView.contentInset = insets; + + [self scrollToBottomAnimated:YES]; + + // Move up control view + // Don't forget the offset related to tabBar + _controlViewBottomConstraint.constant = insets.bottom - [AppDelegate theDelegate].masterTabBarController.tabBar.frame.size.height; +} + +- (void)onKeyboardWillHide:(NSNotification *)notif { + UIEdgeInsets insets = self.messagesTableView.contentInset; + insets.bottom = self.controlView.frame.size.height; + self.messagesTableView.contentInset = insets; + + _controlViewBottomConstraint.constant = 0; +} + +- (void)dismissKeyboard { + // Hide the keyboard + [_messageTextField resignFirstResponder]; + [_roomNameTextField resignFirstResponder]; +} + +#pragma mark - UITableView data source + +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { + return 1; +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + // Check table view members vs messages + if (tableView == self.membersTableView) + { + return members.count; + } + + return messages.count; +} + +- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { + // Check table view members vs messages + if (tableView == self.membersTableView) + { + return 50; + } + + // Compute here height of message cells + CGFloat rowHeight; + // Get event related to this row + MatrixHandler *mxHandler = [MatrixHandler sharedHandler]; + MXEvent *mxEvent = [messages objectAtIndex:indexPath.row]; + + // Check whether the cell will display an attachment or a text message + CGSize contentSize; + NSString *displayText = nil; + if ([mxHandler isAttachment:mxEvent]) { + contentSize = [self attachmentContentSize:mxEvent]; + if (!contentSize.width || !contentSize.height) { + // Check whether unsupported/unexpected messages should be exposed + if ([AppSettings sharedSettings].hideUnsupportedMessages) { + displayText = @""; + } else { + displayText = [NSString stringWithFormat:@"%@%@", kMatrixHandlerUnsupportedMessagePrefix, mxEvent.description]; + } + } + } else { + displayText = [mxHandler displayTextFor:mxEvent inSubtitleMode:NO]; + } + if (displayText) { + contentSize = [self textContentSize:displayText]; + } + + // Check whether the previous message has been sent by the same user. + // We group together messages from the same user. The user's picture and name are displayed only for the first message. + // We consider a new chunk when the user is different from the previous message's one. + BOOL isNewChunk = YES; + if (indexPath.row) { + MXEvent *previousMxEvent = [messages objectAtIndex:indexPath.row - 1]; + if ([previousMxEvent.userId isEqualToString:mxEvent.userId]) { + isNewChunk = NO; + } + } + + // Adjust cell height inside chunk + rowHeight = contentSize.height; + if (isNewChunk) { + // The cell is the first cell of the chunk + rowHeight += ROOM_MESSAGE_CELL_TEXTVIEW_TOP_CONST_DEFAULT; + } else { + // Inside chunk the height of the cell is reduced in order to reduce padding between messages + rowHeight += ROOM_MESSAGE_CELL_TEXTVIEW_TOP_CONST_IN_CHUNK; + } + + // Check whether the message is the last message of the current chunk + BOOL isChunkEnd = YES; + if (indexPath.row < messages.count - 1) { + MXEvent *nextMxEvent = [messages objectAtIndex:indexPath.row + 1]; + if ([nextMxEvent.userId isEqualToString:mxEvent.userId]) { + isChunkEnd = NO; + } + } + + if (!isNewChunk && !isChunkEnd) { + // Reduce again cell height to reduce space with the next cell + rowHeight += ROOM_MESSAGE_CELL_TEXTVIEW_BOTTOM_CONST_GROUPED_CELL; + } else { + // The cell is the first cell of the chunk or the last one + rowHeight += ROOM_MESSAGE_CELL_TEXTVIEW_BOTTOM_CONST_DEFAULT; + } + + if (isNewChunk && isChunkEnd) { + // When the chunk is composed by only one message, we consider the minimun cell height (50) in order to display correctly user's picture + if (rowHeight < 50) { + rowHeight = 50; + } + } + + return rowHeight; +} + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { + MatrixHandler *mxHandler = [MatrixHandler sharedHandler]; + + // Check table view members vs messages + if (tableView == self.membersTableView) { + RoomMemberTableCell *memberCell = [tableView dequeueReusableCellWithIdentifier:@"RoomMemberCell" forIndexPath:indexPath]; + if (indexPath.row < members.count) { + [memberCell setRoomMember:[members objectAtIndex:indexPath.row] withRoom:mxRoom]; + } + + return memberCell; + } + + // Handle here room message cells + RoomMessageTableCell *cell; + MXEvent *mxEvent = [messages objectAtIndex:indexPath.row]; + BOOL isIncomingMsg = NO; + BOOL enableLinkDetection = YES; + + if ([mxEvent.userId isEqualToString:mxHandler.userId]) { + cell = [tableView dequeueReusableCellWithIdentifier:@"OutgoingMessageCell" forIndexPath:indexPath]; + [((OutgoingMessageTableCell*)cell).activityIndicator stopAnimating]; + // Restore initial settings of text view + if (initialAttributedStringForOutgoingMessage == nil) { + initialAttributedStringForOutgoingMessage = cell.messageTextView.attributedText; + } else { + cell.messageTextView.attributedText = initialAttributedStringForOutgoingMessage; + cell.messageTextView.dataDetectorTypes = UIDataDetectorTypeNone; + } + } else { + cell = [tableView dequeueReusableCellWithIdentifier:@"IncomingMessageCell" forIndexPath:indexPath]; + isIncomingMsg = YES; + // Restore initial settings of text view + if (initialAttributedStringForIncomingMessage == nil) { + initialAttributedStringForIncomingMessage = cell.messageTextView.attributedText; + } else { + cell.messageTextView.attributedText = initialAttributedStringForIncomingMessage; + cell.messageTextView.dataDetectorTypes = UIDataDetectorTypeNone; + } + } + + // Restore initial settings of attachment ImageView + cell.attachmentView.imageURL = nil; // Cancel potential attachment loading + cell.attachmentView.hidden = YES; + cell.playIconView.hidden = YES; + // Remove all gesture recognizer + while (cell.attachmentView.gestureRecognizers.count) { + [cell.attachmentView removeGestureRecognizer:cell.attachmentView.gestureRecognizers[0]]; + } + cell.attachmentViewTopAlignmentConstraint.constant = 0; + cell.attachmentViewBottomAlignmentConstraint.constant = 0; + + // Check whether the previous message has been sent by the same user. + // We group together messages from the same user. The user's picture and name are displayed only for the first message. + // We consider a new chunk when the user is different from the previous message's one. + BOOL isNewChunk = YES; + if (indexPath.row) { + MXEvent *previousMxEvent = [messages objectAtIndex:indexPath.row - 1]; + if ([previousMxEvent.userId isEqualToString:mxEvent.userId]) { + isNewChunk = NO; + } + } + + if (isNewChunk) { + // Adjust display of the first message of a chunk + cell.pictureView.hidden = NO; + cell.msgTextViewTopConstraint.constant = ROOM_MESSAGE_CELL_TEXTVIEW_TOP_CONST_DEFAULT; + cell.msgTextViewBottomConstraint.constant = ROOM_MESSAGE_CELL_TEXTVIEW_BOTTOM_CONST_DEFAULT; + cell.messageTextView.contentInset = UIEdgeInsetsZero; + + // Set user's picture + cell.pictureView.placeholder = @"default-profile"; + cell.pictureView.imageURL = [mxRoom.state memberWithUserId:mxEvent.userId].avatarUrl; + [cell.pictureView.layer setCornerRadius:cell.pictureView.frame.size.width / 2]; + cell.pictureView.clipsToBounds = YES; + } else { + // Adjust display of other messages of the chunk + cell.pictureView.hidden = YES; + // The height of this cell has been reduced in order to reduce padding between messages of the same chunk + // We define here a negative constant for the top space between textView and its superview to display correctly the message text. + cell.msgTextViewTopConstraint.constant = ROOM_MESSAGE_CELL_TEXTVIEW_TOP_CONST_IN_CHUNK; + // Shift to the top the displayed message to reduce space with the previous messages + UIEdgeInsets edgeInsets = UIEdgeInsetsZero; + edgeInsets.top = ROOM_MESSAGE_CELL_TEXTVIEW_EDGE_INSET_TOP_IN_CHUNK; + cell.messageTextView.contentInset = edgeInsets; + + // Check whether the next message belongs to the same chunk in order to define bottom space between textView and its superview + cell.msgTextViewBottomConstraint.constant = ROOM_MESSAGE_CELL_TEXTVIEW_BOTTOM_CONST_DEFAULT; + if (indexPath.row < messages.count - 1) { + MXEvent *nextMxEvent = [messages objectAtIndex:indexPath.row + 1]; + if ([nextMxEvent.userId isEqualToString:mxEvent.userId]) { + cell.msgTextViewBottomConstraint.constant = ROOM_MESSAGE_CELL_TEXTVIEW_BOTTOM_CONST_GROUPED_CELL; + } + } + } + + // Update incoming/outgoing message layout + if (isIncomingMsg) { + IncomingMessageTableCell* incomingMsgCell = (IncomingMessageTableCell*)cell; + // Display user's display name for the first meesage of a chunk, except if the name appears in the displayed text (see emote and membership event) + if (isNewChunk && [mxHandler isNotification:mxEvent] == NO) { + incomingMsgCell.userNameLabel.hidden = NO; + incomingMsgCell.userNameLabel.text = [mxRoom.state memberName:mxEvent.userId]; + } else { + incomingMsgCell.userNameLabel.hidden = YES; + } + + // Reset text color + cell.messageTextView.textColor = [UIColor blackColor]; + } else { + OutgoingMessageTableCell* outgoingMsgCell = (OutgoingMessageTableCell*)cell; + // Hide unsent label by default + outgoingMsgCell.unsentLabel.hidden = YES; + + // Set the right text color for outgoing messages + if ([mxEvent.eventId hasPrefix:kLocalEchoEventIdPrefix]) { + cell.messageTextView.textColor = [UIColor lightGrayColor]; + enableLinkDetection = NO; + } else if ([mxEvent.eventId hasPrefix:kFailedEventId]) { + cell.messageTextView.textColor = [UIColor redColor]; + enableLinkDetection = NO; + outgoingMsgCell.unsentLabel.hidden = NO; + // Align unsent label with the textView + outgoingMsgCell.unsentLabelTopConstraint.constant = cell.msgTextViewTopConstraint.constant + cell.messageTextView.contentInset.top - ROOM_MESSAGE_CELL_TEXTVIEW_EDGE_INSET_TOP_IN_CHUNK; + } else { + cell.messageTextView.textColor = [UIColor blackColor]; + } + } + + if ([mxHandler isAttachment:mxEvent]) { + cell.messageTextView.text = nil; // Note: Text view is used as attachment background view + CGSize contentSize = [self attachmentContentSize:mxEvent]; + if (!contentSize.width || !contentSize.height) { + NSLog(@"ERROR: Unsupported message %@", mxEvent.description); + // Check whether unsupported/unexpected messages should be exposed + if ([AppSettings sharedSettings].hideUnsupportedMessages == NO) { + // Display event content as unsupported message + cell.messageTextView.text = [NSString stringWithFormat:@"%@%@", kMatrixHandlerUnsupportedMessagePrefix, mxEvent.description]; + cell.messageTextView.textColor = [UIColor redColor]; + enableLinkDetection = NO; + } + // Adjust constraint constant + cell.msgTextViewWidthConstraint.constant = ROOM_MESSAGE_CELL_MAX_TEXTVIEW_WIDTH; + } else { + cell.attachmentView.hidden = NO; + // Fade attachments during upload + if (isIncomingMsg == NO && [mxEvent.eventId hasPrefix:kLocalEchoEventIdPrefix]) { + cell.attachmentView.alpha = 0.5; + [((OutgoingMessageTableCell*)cell).activityIndicator startAnimating]; + } else { + cell.attachmentView.alpha = 1; + } + + NSString *msgtype = mxEvent.content[@"msgtype"]; + if ([msgtype isEqualToString:kMXMessageTypeImage] || [msgtype isEqualToString:kMXMessageTypeVideo]) { + NSString *url = nil; + if ([msgtype isEqualToString:kMXMessageTypeVideo]) { + cell.playIconView.hidden = NO; + if (mxEvent.content[@"info"]) { + url = mxEvent.content[@"info"][@"thumbnail_url"]; + } + } else { + url = mxEvent.content[@"thumbnail_url"]; + } + + if (url == nil) { + url = mxEvent.content[@"url"]; + } + cell.attachmentView.imageURL = url; + + // Add tap recognizer to open attachment + UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(showAttachmentView:)]; + [tap setNumberOfTouchesRequired:1]; + [tap setNumberOfTapsRequired:1]; + [tap setDelegate:self]; + [cell.attachmentView addGestureRecognizer:tap]; + // Store attachment content description used in showAttachmentView: + cell.attachmentView.mediaInfo = mxEvent.content; + } else { + cell.attachmentView.imageURL = nil; + } + + // Adjust constraint constant + cell.msgTextViewWidthConstraint.constant = contentSize.width; + // Align attachment inside text view by considering text view edge inset + cell.attachmentViewTopAlignmentConstraint.constant = ROOM_MESSAGE_CELL_IMAGE_MARGIN + cell.messageTextView.contentInset.top; + cell.attachmentViewBottomAlignmentConstraint.constant = -ROOM_MESSAGE_CELL_IMAGE_MARGIN + cell.messageTextView.contentInset.top; + } + } else { + NSString *displayText = [mxHandler displayTextFor:mxEvent inSubtitleMode:NO]; + // Update text color according to text content + if ([displayText hasPrefix:kMatrixHandlerUnsupportedMessagePrefix]) { + cell.messageTextView.textColor = [UIColor redColor]; + enableLinkDetection = NO; + } else if (isIncomingMsg && ([displayText rangeOfString:mxHandler.userDisplayName options:NSCaseInsensitiveSearch].location != NSNotFound || [displayText rangeOfString:mxHandler.userId options:NSCaseInsensitiveSearch].location != NSNotFound)) { + cell.messageTextView.textColor = [UIColor blueColor]; + } + cell.messageTextView.text = displayText; + // Adjust textView width constraint + cell.msgTextViewWidthConstraint.constant = [self textContentSize:displayText].width; + } + + // Turn on link detection only when it is usefull + if (enableLinkDetection) { + cell.messageTextView.dataDetectorTypes = UIDataDetectorTypeLink; + } + + // Handle timestamp display + if (dateFormatter && mxEvent.originServerTs) { + cell.dateTimeLabel.hidden = NO; + NSDate *date = [NSDate dateWithTimeIntervalSince1970:mxEvent.originServerTs/1000]; + cell.dateTimeLabel.text = [dateFormatter stringFromDate:date]; + // Align dateTime label with the textView + cell.dateTimeLabelTopConstraint.constant = cell.msgTextViewTopConstraint.constant + cell.messageTextView.contentInset.top - ROOM_MESSAGE_CELL_TEXTVIEW_EDGE_INSET_TOP_IN_CHUNK; + } else { + cell.dateTimeLabel.hidden = YES; + } + + return cell; +} + +- (CGSize)textContentSize:(NSString*)textMsg { + // Use a TextView template to compute cell height + UITextView *dummyTextView = [[UITextView alloc] initWithFrame:CGRectMake(0, 0, ROOM_MESSAGE_CELL_MAX_TEXTVIEW_WIDTH, MAXFLOAT)]; + dummyTextView.font = [UIFont systemFontOfSize:14]; + dummyTextView.text = textMsg; + return [dummyTextView sizeThatFits:dummyTextView.frame.size]; +} + +- (CGSize)attachmentContentSize:(MXEvent*)mxEvent { + CGSize contentSize; + NSString *msgtype = mxEvent.content[@"msgtype"]; + if ([msgtype isEqualToString:kMXMessageTypeImage] || [msgtype isEqualToString:kMXMessageTypeVideo]) { + CGFloat width, height; + width = height = 0; + + NSDictionary *thumbInfo = nil; + if ([msgtype isEqualToString:kMXMessageTypeVideo]) { + if (mxEvent.content[@"info"]) { + thumbInfo = mxEvent.content[@"info"][@"thumbnail_info"]; + } + } else { + thumbInfo = mxEvent.content[@"thumbnail_info"]; + } + + if (thumbInfo) { + width = [thumbInfo[@"w"] integerValue] + 2 * ROOM_MESSAGE_CELL_IMAGE_MARGIN; + height = [thumbInfo[@"h"] integerValue] + 2 * ROOM_MESSAGE_CELL_IMAGE_MARGIN; + if (width > ROOM_MESSAGE_CELL_MAX_TEXTVIEW_WIDTH || height > ROOM_MESSAGE_CELL_MAX_TEXTVIEW_WIDTH) { + if (width > height) { + height = (height * ROOM_MESSAGE_CELL_MAX_TEXTVIEW_WIDTH) / width; + height = floorf(height / 2) * 2; + width = ROOM_MESSAGE_CELL_MAX_TEXTVIEW_WIDTH; + } else { + width = (width * ROOM_MESSAGE_CELL_MAX_TEXTVIEW_WIDTH) / height; + width = floorf(width / 2) * 2; + height = ROOM_MESSAGE_CELL_MAX_TEXTVIEW_WIDTH; + } + } + } + contentSize = CGSizeMake(width, height); + } else { + contentSize = CGSizeMake(40, 40); + } + return contentSize; +} + +#pragma mark - UITableView delegate + +- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { + // Check table view members vs messages + if (tableView == self.membersTableView) { + // List action(s) available on this member + // TODO: Check user's power level before allowing an action (kick, ban, ...) + MXRoomMember *roomMember = [members objectAtIndex:indexPath.row]; + MatrixHandler *mxHandler = [MatrixHandler sharedHandler]; + __weak typeof(self) weakSelf = self; + if (self.actionMenu) { + [self.actionMenu dismiss:NO]; + self.actionMenu = nil; + } + + // Consider the case of the user himself + if ([roomMember.userId isEqualToString:mxHandler.userId]) { + self.actionMenu = [[CustomAlert alloc] initWithTitle:@"Select an action:" message:nil style:CustomAlertStyleActionSheet]; + [self.actionMenu addActionWithTitle:@"Leave" style:CustomAlertActionStyleDefault handler:^(CustomAlert *alert) { + if (weakSelf) { + weakSelf.actionMenu = nil; + MXRoom *currentRoom = [[MatrixHandler sharedHandler].mxSession room:weakSelf.roomId]; + [currentRoom leave:^{ + // Back to recents + [weakSelf.navigationController popViewControllerAnimated:YES]; + } failure:^(NSError *error) { + NSLog(@"Leave room %@ failed: %@", weakSelf.roomId, error); + //Alert user + [[AppDelegate theDelegate] showErrorAsAlert:error]; + }]; + } + }]; + } else { + // Consider membership of the selected member + switch (roomMember.membership) { + case MXMembershipInvite: + case MXMembershipJoin: { + self.actionMenu = [[CustomAlert alloc] initWithTitle:@"Select an action:" message:nil style:CustomAlertStyleActionSheet]; + [self.actionMenu addActionWithTitle:@"Kick" style:CustomAlertActionStyleDefault handler:^(CustomAlert *alert) { + if (weakSelf) { + weakSelf.actionMenu = nil; + [[MatrixHandler sharedHandler].mxRestClient kickUser:roomMember.userId + fromRoom:weakSelf.roomId + reason:nil + success:^{ + } + failure:^(NSError *error) { + NSLog(@"Kick %@ failed: %@", roomMember.userId, error); + //Alert user + [[AppDelegate theDelegate] showErrorAsAlert:error]; + }]; + } + }]; + [self.actionMenu addActionWithTitle:@"Ban" style:CustomAlertActionStyleDefault handler:^(CustomAlert *alert) { + if (weakSelf) { + weakSelf.actionMenu = nil; + [[MatrixHandler sharedHandler].mxRestClient banUser:roomMember.userId + inRoom:weakSelf.roomId + reason:nil + success:^{ + } + failure:^(NSError *error) { + NSLog(@"Ban %@ failed: %@", roomMember.userId, error); + //Alert user + [[AppDelegate theDelegate] showErrorAsAlert:error]; + }]; + } + }]; + break; + } + case MXMembershipLeave: { + self.actionMenu = [[CustomAlert alloc] initWithTitle:@"Select an action:" message:nil style:CustomAlertStyleActionSheet]; + [self.actionMenu addActionWithTitle:@"Invite" style:CustomAlertActionStyleDefault handler:^(CustomAlert *alert) { + if (weakSelf) { + weakSelf.actionMenu = nil; + [[MatrixHandler sharedHandler].mxRestClient inviteUser:roomMember.userId + toRoom:weakSelf.roomId + success:^{ + } + failure:^(NSError *error) { + NSLog(@"Invite %@ failed: %@", roomMember.userId, error); + //Alert user + [[AppDelegate theDelegate] showErrorAsAlert:error]; + }]; + } + }]; + [self.actionMenu addActionWithTitle:@"Ban" style:CustomAlertActionStyleDefault handler:^(CustomAlert *alert) { + if (weakSelf) { + weakSelf.actionMenu = nil; + [[MatrixHandler sharedHandler].mxRestClient banUser:roomMember.userId + inRoom:weakSelf.roomId + reason:nil + success:^{ + } + failure:^(NSError *error) { + NSLog(@"Ban %@ failed: %@", roomMember.userId, error); + //Alert user + [[AppDelegate theDelegate] showErrorAsAlert:error]; + }]; + } + }]; + break; + } + case MXMembershipBan: { + self.actionMenu = [[CustomAlert alloc] initWithTitle:@"Select an action:" message:nil style:CustomAlertStyleActionSheet]; + [self.actionMenu addActionWithTitle:@"Unban" style:CustomAlertActionStyleDefault handler:^(CustomAlert *alert) { + if (weakSelf) { + weakSelf.actionMenu = nil; + [[MatrixHandler sharedHandler].mxRestClient unbanUser:roomMember.userId + inRoom:weakSelf.roomId + success:^{ + } + failure:^(NSError *error) { + NSLog(@"Unban %@ failed: %@", roomMember.userId, error); + //Alert user + [[AppDelegate theDelegate] showErrorAsAlert:error]; + }]; + } + }]; + break; + } + default: { + break; + } + } + } + + // Display the action sheet (if any) + if (self.actionMenu) { + self.actionMenu.cancelButtonIndex = [self.actionMenu addActionWithTitle:@"Cancel" style:CustomAlertActionStyleDefault handler:^(CustomAlert *alert) { + weakSelf.actionMenu = nil; + }]; + [self.actionMenu showInViewController:self]; + } + + [tableView deselectRowAtIndexPath:indexPath animated:YES]; + } else if (tableView == self.messagesTableView) { + // Dismiss keyboard when user taps on messages table view content + [self dismissKeyboard]; + } +} + +// Detect vertical bounce at the top of the tableview to trigger pagination +- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset { + if (scrollView == self.messagesTableView) { + // paginate ? + if (scrollView.contentOffset.y < -64) + { + [self triggerBackPagination]; + } + } +} + +#pragma mark - UITextField delegate + +- (void)onTextFieldChange:(NSNotification *)notif { + NSString *msg = _messageTextField.text; + + if (msg.length) { + _sendBtn.enabled = YES; + _sendBtn.alpha = 1; + // Reset potential placeholder (used in case of wrong command usage) + _messageTextField.placeholder = nil; + } else { + _sendBtn.enabled = NO; + _sendBtn.alpha = 0.5; + } +} + +- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField { + if (textField == self.roomNameTextField) { + self.roomNameTextField.borderStyle = UITextBorderStyleRoundedRect; + self.roomNameTextField.backgroundColor = [UIColor whiteColor]; + } + return YES; +} + +- (void)textFieldDidEndEditing:(UITextField *)textField { + if (textField == self.roomNameTextField) { + self.roomNameTextField.borderStyle = UITextBorderStyleNone; + self.roomNameTextField.backgroundColor = [UIColor clearColor]; + } +} + +- (BOOL)textFieldShouldReturn:(UITextField*) textField { + // "Done" key has been pressed + [textField resignFirstResponder]; + + if (textField == self.roomNameTextField) { + NSString *roomName = self.roomNameTextField.text; + if ([roomName isEqualToString:mxRoom.state.name] == NO) { + [self.activityIndicator startAnimating]; + MatrixHandler *mxHandler = [MatrixHandler sharedHandler]; + [mxHandler.mxRestClient setRoomName:self.roomId name:roomName success:^{ + if (isBackPaginationInProgress == NO) { + [self.activityIndicator stopAnimating]; + } + } failure:^(NSError *error) { + if (isBackPaginationInProgress == NO) { + [self.activityIndicator stopAnimating]; + } + // Revert change + self.roomNameTextField.text = mxRoom.state.displayname; + NSLog(@"Rename room failed: %@", error); + //Alert user + [[AppDelegate theDelegate] showErrorAsAlert:error]; + }]; + } + } + return YES; +} + +#pragma mark - Actions + +- (IBAction)onButtonPressed:(id)sender { + if (sender == _sendBtn) { + NSString *msgTxt = self.messageTextField.text; + + // Handle potential commands in room chat + if ([self isIRCStyleCommand:msgTxt] == NO) { + [self postTextMessage:msgTxt]; + } + + self.messageTextField.text = nil; + // disable send button + [self onTextFieldChange:nil]; + } else if (sender == _optionBtn) { + [self dismissKeyboard]; + + // Display action menu: Add attachments, Invite user... + __weak typeof(self) weakSelf = self; + self.actionMenu = [[CustomAlert alloc] initWithTitle:@"Select an action:" message:nil style:CustomAlertStyleActionSheet]; + // Attachments + [self.actionMenu addActionWithTitle:@"Attach" style:CustomAlertActionStyleDefault handler:^(CustomAlert *alert) { + if (weakSelf) { + // Ask for attachment type + weakSelf.actionMenu = [[CustomAlert alloc] initWithTitle:@"Select an attachment type:" message:nil style:CustomAlertStyleActionSheet]; + [weakSelf.actionMenu addActionWithTitle:@"Media" style:CustomAlertActionStyleDefault handler:^(CustomAlert *alert) { + if (weakSelf) { + weakSelf.actionMenu = nil; + // Open media gallery + UIImagePickerController *mediaPicker = [[UIImagePickerController alloc] init]; + mediaPicker.delegate = weakSelf; + mediaPicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary; + mediaPicker.allowsEditing = NO; + mediaPicker.mediaTypes = [NSArray arrayWithObjects:(NSString *)kUTTypeImage, (NSString *)kUTTypeMovie, nil]; + [[AppDelegate theDelegate].masterTabBarController presentMediaPicker:mediaPicker]; + } + }]; + weakSelf.actionMenu.cancelButtonIndex = [weakSelf.actionMenu addActionWithTitle:@"Cancel" style:CustomAlertActionStyleDefault handler:^(CustomAlert *alert) { + weakSelf.actionMenu = nil; + }]; + [weakSelf.actionMenu showInViewController:weakSelf]; + } + }]; + // Invitation + [self.actionMenu addActionWithTitle:@"Invite" style:CustomAlertActionStyleDefault handler:^(CustomAlert *alert) { + if (weakSelf) { + // Ask for userId to invite + weakSelf.actionMenu = [[CustomAlert alloc] initWithTitle:@"User ID:" message:nil style:CustomAlertStyleAlert]; + weakSelf.actionMenu.cancelButtonIndex = [weakSelf.actionMenu addActionWithTitle:@"Cancel" style:CustomAlertActionStyleDefault handler:^(CustomAlert *alert) { + weakSelf.actionMenu = nil; + }]; + [weakSelf.actionMenu addTextFieldWithConfigurationHandler:^(UITextField *textField) { + textField.secureTextEntry = NO; + textField.placeholder = @"ex: @bob:homeserver"; + }]; + [weakSelf.actionMenu addActionWithTitle:@"Invite" style:CustomAlertActionStyleDefault handler:^(CustomAlert *alert) { + UITextField *textField = [alert textFieldAtIndex:0]; + NSString *userId = textField.text; + weakSelf.actionMenu = nil; + if (userId.length) { + [[MatrixHandler sharedHandler].mxRestClient inviteUser:userId toRoom:weakSelf.roomId success:^{ + + } failure:^(NSError *error) { + NSLog(@"Invite %@ failed: %@", userId, error); + //Alert user + [[AppDelegate theDelegate] showErrorAsAlert:error]; + }]; + } + }]; + [weakSelf.actionMenu showInViewController:weakSelf]; + } + }]; + self.actionMenu.cancelButtonIndex = [self.actionMenu addActionWithTitle:@"Cancel" style:CustomAlertActionStyleDefault handler:^(CustomAlert *alert) { + weakSelf.actionMenu = nil; + }]; + weakSelf.actionMenu.sourceView = weakSelf.optionBtn; + [self.actionMenu showInViewController:self]; + } +} + +- (IBAction)showHideDateTime:(id)sender { + if (dateFormatter) { + // dateTime will be hidden + dateFormatter = nil; + } else { + // dateTime will be visible + NSString *dateFormat = @"MMM dd HH:mm"; + dateFormatter = [[NSDateFormatter alloc] init]; + [dateFormatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:[[[NSBundle mainBundle] preferredLocalizations] objectAtIndex:0]]]; + [dateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4]; + [dateFormatter setTimeStyle:NSDateFormatterNoStyle]; + [dateFormatter setDateFormat:dateFormat]; + } + + [self.messagesTableView reloadData]; +} + +#pragma mark - Post messages + +- (void)postMessage:(NSDictionary*)msgContent withLocalEventId:(NSString*)localEventId { + MXMessageType msgType = msgContent[@"msgtype"]; + if (msgType) { + // Check whether a temporary event has already been added for local echo (this happens on attachments) + MXEvent *mxEvent = nil; + if (localEventId) { + // Update the temporary event with the actual msg content + NSUInteger index = messages.count; + while (index--) { + mxEvent = [messages objectAtIndex:index]; + if ([mxEvent.eventId isEqualToString:localEventId]) { + mxEvent.content = msgContent; + // Refresh table display + NSIndexPath *indexPath = [NSIndexPath indexPathForRow:index inSection:0]; + [self.messagesTableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone]; + break; + } + } + } else { + // Create a temporary event to displayed outgoing message (local echo) + localEventId = [NSString stringWithFormat:@"%@%@", kLocalEchoEventIdPrefix, [[NSProcessInfo processInfo] globallyUniqueString]]; + mxEvent = [[MXEvent alloc] init]; + mxEvent.roomId = self.roomId; + mxEvent.eventId = localEventId; + mxEvent.eventType = MXEventTypeRoomMessage; + mxEvent.type = kMXEventTypeStringRoomMessage; + mxEvent.content = msgContent; + mxEvent.userId = [MatrixHandler sharedHandler].userId; + // Update table sources + NSIndexPath *indexPath = [NSIndexPath indexPathForRow:messages.count inSection:0]; + [messages addObject:mxEvent]; + // Refresh table display (Disable animation during cells insertion to prevent flickering) + [UIView setAnimationsEnabled:NO]; + [self.messagesTableView beginUpdates]; + if (indexPath.row > 0) { + NSIndexPath *prevIndexPath = [NSIndexPath indexPathForRow:indexPath.row - 1 inSection:0]; + [self.messagesTableView reloadRowsAtIndexPaths:@[prevIndexPath] withRowAnimation:UITableViewRowAnimationNone]; + } + [self.messagesTableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone]; + [self.messagesTableView endUpdates]; + [UIView setAnimationsEnabled:YES]; + + [self scrollToBottomAnimated:NO]; + } + + // Send message to the room + [[[MatrixHandler sharedHandler] mxRestClient] postMessageToRoom:self.roomId msgType:msgType content:mxEvent.content success:^(NSString *event_id) { + // Update the temporary event with the actual event id + NSUInteger index = messages.count; + while (index--) { + MXEvent *mxEvent = [messages objectAtIndex:index]; + if ([mxEvent.eventId isEqualToString:localEventId]) { + mxEvent.eventId = event_id; + // Refresh table display + NSIndexPath *indexPath = [NSIndexPath indexPathForRow:index inSection:0]; + [self.messagesTableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone]; + break; + } + } + } failure:^(NSError *error) { + [self handleError:error forLocalEventId:localEventId]; + }]; + } +} + +- (void)postTextMessage:(NSString*)msgTxt { + MXMessageType msgType = kMXMessageTypeText; + // Check whether the message is an emote + if ([msgTxt hasPrefix:@"/me "]) { + msgType = kMXMessageTypeEmote; + // Remove "/me " string + msgTxt = [msgTxt substringFromIndex:4]; + } + + [self postMessage:@{@"msgtype":msgType, @"body":msgTxt} withLocalEventId:nil]; +} + +- (NSString*)addLocalEventForAttachedImage:(UIImage*)image { + // Create a temporary event to displayed outgoing message (local echo) + NSString *localEventId = [NSString stringWithFormat:@"%@%@", kLocalEchoEventIdPrefix, [[NSProcessInfo processInfo] globallyUniqueString]]; + MXEvent *mxEvent = [[MXEvent alloc] init]; + mxEvent.roomId = self.roomId; + mxEvent.eventId = localEventId; + mxEvent.eventType = MXEventTypeRoomMessage; + mxEvent.type = kMXEventTypeStringRoomMessage; + // We store temporarily the image in cache, use the localId to build temporary url + NSString *dummyURL = [NSString stringWithFormat:@"%@%@", kMediaManagerPrefixForDummyURL, localEventId]; + NSData *imageData = UIImageJPEGRepresentation(image, 0.5); + NSString *cacheFilePath = [MediaManager cacheMediaData:imageData forURL:dummyURL mimeType:@"image/jpeg"]; + if (cacheFilePath) { + if (tmpCachedAttachments == nil) { + tmpCachedAttachments = [NSMutableArray array]; + } + [tmpCachedAttachments addObject:cacheFilePath]; + } + NSMutableDictionary *thumbnailInfo = [[NSMutableDictionary alloc] init]; + [thumbnailInfo setValue:@"image/jpeg" forKey:@"mimetype"]; + [thumbnailInfo setValue:[NSNumber numberWithUnsignedInteger:(NSUInteger)image.size.width] forKey:@"w"]; + [thumbnailInfo setValue:[NSNumber numberWithUnsignedInteger:(NSUInteger)image.size.height] forKey:@"h"]; + [thumbnailInfo setValue:[NSNumber numberWithUnsignedInteger:imageData.length] forKey:@"size"]; + mxEvent.content = @{@"msgtype":@"m.image", @"thumbnail_info":thumbnailInfo, @"thumbnail_url":dummyURL}; + mxEvent.userId = [MatrixHandler sharedHandler].userId; + + // Update table sources + NSIndexPath *indexPath = [NSIndexPath indexPathForRow:messages.count inSection:0]; + [messages addObject:mxEvent]; + + // Refresh table display (Disable animation during cells insertion to prevent flickering) + [UIView setAnimationsEnabled:NO]; + [self.messagesTableView beginUpdates]; + if (indexPath.row > 0) { + NSIndexPath *prevIndexPath = [NSIndexPath indexPathForRow:indexPath.row - 1 inSection:0]; + [self.messagesTableView reloadRowsAtIndexPaths:@[prevIndexPath] withRowAnimation:UITableViewRowAnimationNone]; + } + [self.messagesTableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone]; + [self.messagesTableView endUpdates]; + [UIView setAnimationsEnabled:YES]; + + [self scrollToBottomAnimated:NO]; + return localEventId; +} + +- (void)handleError:(NSError *)error forLocalEventId:(NSString *)localEventId { + NSLog(@"Post message failed: %@", error); + if (error) { + // Alert user + [[AppDelegate theDelegate] showErrorAsAlert:error]; + } + + // Update the temporary event with this local event id + NSUInteger index = messages.count; + while (index--) { + MXEvent *mxEvent = [messages objectAtIndex:index]; + if ([mxEvent.eventId isEqualToString:localEventId]) { + NSLog(@"Posted event: %@", mxEvent.description); + mxEvent.eventId = kFailedEventId; + // Refresh table display + NSIndexPath *indexPath = [NSIndexPath indexPathForRow:index inSection:0]; + [self.messagesTableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone]; + break; + } + } +} + +- (BOOL)isIRCStyleCommand:(NSString*)text{ + // Check whether the provided text may be an IRC-style command + if ([text hasPrefix:@"/"] == NO || [text hasPrefix:@"//"] == YES) { + return NO; + } + + // Parse command line + NSArray *components = [text componentsSeparatedByString:@" "]; + NSString *cmd = [components objectAtIndex:0]; + NSUInteger index = 1; + + if ([cmd isEqualToString:kCmdEmote]) { + // post message as an emote + [self postTextMessage:text]; + } else if ([text hasPrefix:kCmdChangeDisplayName]) { + // Change display name + NSString *displayName = [text substringFromIndex:kCmdChangeDisplayName.length + 1]; + // Remove white space from both ends + displayName = [displayName stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; + + if (displayName.length) { + MatrixHandler *mxHandler = [MatrixHandler sharedHandler]; + [mxHandler.mxRestClient setDisplayName:displayName success:^{ + } failure:^(NSError *error) { + NSLog(@"Set displayName failed: %@", error); + //Alert user + [[AppDelegate theDelegate] showErrorAsAlert:error]; + }]; + } else { + // Display cmd usage in text input as placeholder + self.messageTextField.placeholder = @"Usage: /nick "; + } + } else if ([text hasPrefix:kCmdJoinRoom]) { + // Join a room + NSString *roomAlias = [text substringFromIndex:kCmdJoinRoom.length + 1]; + // Remove white space from both ends + roomAlias = [roomAlias stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; + + // Check + if (roomAlias.length) { + // FIXME + NSLog(@"Join Alias is not supported yet (%@)", text); + UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"/join is not supported yet" message:nil delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil]; + [alert show]; + } else { + // Display cmd usage in text input as placeholder + self.messageTextField.placeholder = @"Usage: /join "; + } + } else { + // Retrieve userId + NSString *userId = nil; + while (index < components.count) { + userId = [components objectAtIndex:index++]; + if (userId.length) { + // done + break; + } + // reset + userId = nil; + } + + if ([cmd isEqualToString:kCmdKickUser]) { + if (userId) { + // Retrieve potential reason + NSString *reason = nil; + while (index < components.count) { + if (reason) { + reason = [NSString stringWithFormat:@"%@ %@", reason, [components objectAtIndex:index++]]; + } else { + reason = [components objectAtIndex:index++]; + } + } + // Kick the user + MatrixHandler *mxHandler = [MatrixHandler sharedHandler]; + [mxHandler.mxRestClient kickUser:userId fromRoom:self.roomId reason:reason success:^{ + } failure:^(NSError *error) { + NSLog(@"Kick user (%@) failed: %@", userId, error); + //Alert user + [[AppDelegate theDelegate] showErrorAsAlert:error]; + }]; + } else { + // Display cmd usage in text input as placeholder + self.messageTextField.placeholder = @"Usage: /kick []"; + } + } else if ([cmd isEqualToString:kCmdBanUser]) { + if (userId) { + // Retrieve potential reason + NSString *reason = nil; + while (index < components.count) { + if (reason) { + reason = [NSString stringWithFormat:@"%@ %@", reason, [components objectAtIndex:index++]]; + } else { + reason = [components objectAtIndex:index++]; + } + } + // Ban the user + MatrixHandler *mxHandler = [MatrixHandler sharedHandler]; + [mxHandler.mxRestClient banUser:userId inRoom:self.roomId reason:reason success:^{ + } failure:^(NSError *error) { + NSLog(@"Ban user (%@) failed: %@", userId, error); + //Alert user + [[AppDelegate theDelegate] showErrorAsAlert:error]; + }]; + } else { + // Display cmd usage in text input as placeholder + self.messageTextField.placeholder = @"Usage: /ban []"; + } + } else if ([cmd isEqualToString:kCmdUnbanUser]) { + if (userId) { + // Unban the user + MatrixHandler *mxHandler = [MatrixHandler sharedHandler]; + [mxHandler.mxRestClient unbanUser:userId inRoom:self.roomId success:^{ + } failure:^(NSError *error) { + NSLog(@"Unban user (%@) failed: %@", userId, error); + //Alert user + [[AppDelegate theDelegate] showErrorAsAlert:error]; + }]; + } else { + // Display cmd usage in text input as placeholder + self.messageTextField.placeholder = @"Usage: /unban "; + } + } else if ([cmd isEqualToString:kCmdSetUserPowerLevel]) { + // Retrieve power level + NSString *powerLevel = nil; + while (index < components.count) { + powerLevel = [components objectAtIndex:index++]; + if (powerLevel.length) { + // done + break; + } + // reset + powerLevel = nil; + } + // Set power level + if (userId && powerLevel) { + // FIXME + NSLog(@"Set user power level (/op) is not supported yet (%@)", userId); + UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"/op is not supported yet" message:nil delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil]; + [alert show]; + } else { + // Display cmd usage in text input as placeholder + self.messageTextField.placeholder = @"Usage: /op "; + } + } else if ([cmd isEqualToString:kCmdResetUserPowerLevel]) { + if (userId) { + // Reset user power level + // FIXME + NSLog(@"Reset user power level (/deop) is not supported yet (%@)", userId); + UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"/deop is not supported yet" message:nil delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil]; + [alert show]; + } else { + // Display cmd usage in text input as placeholder + self.messageTextField.placeholder = @"Usage: /deop "; + } + } else { + NSLog(@"Unrecognised IRC-style command: %@", text); + self.messageTextField.placeholder = [NSString stringWithFormat:@"Unrecognised IRC-style command: %@", cmd]; + } + } + return YES; +} + +# pragma mark - UIImagePickerControllerDelegate + +- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info { + NSString *mediaType = [info objectForKey:UIImagePickerControllerMediaType]; + if ([mediaType isEqualToString:(NSString *)kUTTypeImage]) { + UIImage *selectedImage = [info objectForKey:UIImagePickerControllerOriginalImage]; + if (selectedImage) { + NSString * localEventId = [self addLocalEventForAttachedImage:selectedImage]; + // Upload image and its thumbnail + MatrixHandler *mxHandler = [MatrixHandler sharedHandler]; + NSUInteger thumbnailSize = ROOM_MESSAGE_CELL_MAX_TEXTVIEW_WIDTH - 2 * ROOM_MESSAGE_CELL_IMAGE_MARGIN; + [mxHandler.mxRestClient uploadImage:selectedImage thumbnailSize:thumbnailSize timeout:30 success:^(NSDictionary *imageMessage) { + // Send image + [self postMessage:imageMessage withLocalEventId:localEventId]; + } failure:^(NSError *error) { + [self handleError:error forLocalEventId:localEventId]; + }]; + } + } else if ([mediaType isEqualToString:(NSString *)kUTTypeMovie]) { + NSURL* selectedVideo = [info objectForKey:UIImagePickerControllerMediaURL]; + if (selectedVideo) { + // Create video thumbnail + MPMoviePlayerController* moviePlayerController = [[MPMoviePlayerController alloc] initWithContentURL:selectedVideo]; + if (moviePlayerController) { + [moviePlayerController setShouldAutoplay:NO]; + UIImage* videoThumbnail = [moviePlayerController thumbnailImageAtTime:(NSTimeInterval)1 timeOption:MPMovieTimeOptionNearestKeyFrame]; + [moviePlayerController stop]; + moviePlayerController = nil; + + if (videoThumbnail) { + // Prepare video thumbnail description + NSUInteger thumbnailSize = ROOM_MESSAGE_CELL_MAX_TEXTVIEW_WIDTH - 2 * ROOM_MESSAGE_CELL_IMAGE_MARGIN; + UIImage *thumbnail = [MediaManager resize:videoThumbnail toFitInSize:CGSizeMake(thumbnailSize, thumbnailSize)]; + NSMutableDictionary *thumbnailInfo = [[NSMutableDictionary alloc] init]; + [thumbnailInfo setValue:@"image/jpeg" forKey:@"mimetype"]; + [thumbnailInfo setValue:[NSNumber numberWithUnsignedInteger:(NSUInteger)thumbnail.size.width] forKey:@"w"]; + [thumbnailInfo setValue:[NSNumber numberWithUnsignedInteger:(NSUInteger)thumbnail.size.height] forKey:@"h"]; + NSData *thumbnailData = UIImageJPEGRepresentation(thumbnail, 0.9); + [thumbnailInfo setValue:[NSNumber numberWithUnsignedInteger:thumbnailData.length] forKey:@"size"]; + + // Create the local event displayed during uploading + NSString * localEventId = [self addLocalEventForAttachedImage:thumbnail]; + + // Upload thumbnail + MatrixHandler *mxHandler = [MatrixHandler sharedHandler]; + [mxHandler.mxRestClient uploadContent:thumbnailData mimeType:@"image/jpeg" timeout:30 success:^(NSString *url) { + // Prepare content of attached video + NSMutableDictionary *videoContent = [[NSMutableDictionary alloc] init]; + NSMutableDictionary *videoInfo = [[NSMutableDictionary alloc] init]; + [videoContent setValue:@"m.video" forKey:@"msgtype"]; + [videoInfo setValue:url forKey:@"thumbnail_url"]; + [videoInfo setValue:thumbnailInfo forKey:@"thumbnail_info"]; + + // Convert video container to mp4 + AVURLAsset* videoAsset = [AVURLAsset URLAssetWithURL:selectedVideo options:nil]; + AVAssetExportSession *exportSession = [AVAssetExportSession exportSessionWithAsset:videoAsset presetName:AVAssetExportPresetMediumQuality]; + // Set output URL + NSString * outputFileName = [NSString stringWithFormat:@"%.0f.mp4",[[NSDate date] timeIntervalSince1970]]; + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); + NSString *cacheRoot = [paths objectAtIndex:0]; + NSURL *tmpVideoLocation = [NSURL fileURLWithPath:[cacheRoot stringByAppendingPathComponent:outputFileName]]; + exportSession.outputURL = tmpVideoLocation; + // Check supported output file type + NSArray *supportedFileTypes = exportSession.supportedFileTypes; + if ([supportedFileTypes containsObject:AVFileTypeMPEG4]) { + exportSession.outputFileType = AVFileTypeMPEG4; + [videoInfo setValue:@"video/mp4" forKey:@"mimetype"]; + } else { + NSLog(@"Unexpected case: MPEG-4 file format is not supported"); + // we send QuickTime movie file by default + exportSession.outputFileType = AVFileTypeQuickTimeMovie; + [videoInfo setValue:@"video/quicktime" forKey:@"mimetype"]; + } + // Export video file and send it + [exportSession exportAsynchronouslyWithCompletionHandler:^{ + // Check status + if ([exportSession status] == AVAssetExportSessionStatusCompleted) { + AVURLAsset* asset = [AVURLAsset URLAssetWithURL:tmpVideoLocation + options:[NSDictionary dictionaryWithObjectsAndKeys: + [NSNumber numberWithBool:YES], + AVURLAssetPreferPreciseDurationAndTimingKey, + nil] + ]; + + [videoInfo setValue:[NSNumber numberWithDouble:(1000 * CMTimeGetSeconds(asset.duration))] forKey:@"duration"]; + NSArray *videoTracks = [asset tracksWithMediaType:AVMediaTypeVideo]; + if (videoTracks.count > 0) { + AVAssetTrack *videoTrack = [videoTracks objectAtIndex:0]; + CGSize videoSize = videoTrack.naturalSize; + [videoInfo setValue:[NSNumber numberWithUnsignedInteger:(NSUInteger)videoSize.width] forKey:@"w"]; + [videoInfo setValue:[NSNumber numberWithUnsignedInteger:(NSUInteger)videoSize.height] forKey:@"h"]; + } + + // Upload the video + NSData *videoData = [NSData dataWithContentsOfURL:tmpVideoLocation]; + [[NSFileManager defaultManager] removeItemAtPath:[tmpVideoLocation path] error:nil]; + if (videoData) { + if (videoData.length < UPLOAD_FILE_SIZE) { + [videoInfo setValue:[NSNumber numberWithUnsignedInteger:videoData.length] forKey:@"size"]; + [mxHandler.mxRestClient uploadContent:videoData mimeType:videoInfo[@"mimetype"] timeout:30 success:^(NSString *url) { + [videoContent setValue:url forKey:@"url"]; + [videoContent setValue:videoInfo forKey:@"info"]; + [videoContent setValue:@"Video" forKey:@"body"]; + [self postMessage:videoContent withLocalEventId:localEventId]; + } failure:^(NSError *error) { + [self handleError:error forLocalEventId:localEventId]; + }]; + } else { + NSLog(@"Video is too large"); + [self handleError:nil forLocalEventId:localEventId]; + } + } else { + NSLog(@"Attach video failed: no data"); + [self handleError:nil forLocalEventId:localEventId]; + } + } + else { + NSLog(@"Video export failed: %d", [exportSession status]); + // remove tmp file (if any) + [[NSFileManager defaultManager] removeItemAtPath:[tmpVideoLocation path] error:nil]; + [self handleError:nil forLocalEventId:localEventId]; + } + }]; + } failure:^(NSError *error) { + NSLog(@"Video thumbnail upload failed"); + [self handleError:error forLocalEventId:localEventId]; + }]; + } + } + } + } + + [self dismissMediaPicker]; +} + +- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker { + [self dismissMediaPicker]; +} + +- (void)dismissMediaPicker { + [[AppDelegate theDelegate].masterTabBarController dismissMediaPicker]; +} +@end diff --git a/matrixConsole/ViewController/SettingsViewController.h b/matrixConsole/ViewController/SettingsViewController.h new file mode 100644 index 000000000..929b88734 --- /dev/null +++ b/matrixConsole/ViewController/SettingsViewController.h @@ -0,0 +1,24 @@ +/* + Copyright 2014 OpenMarket 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 + +@interface SettingsViewController : UITableViewController + +- (void)reset; + +@end + diff --git a/matrixConsole/ViewController/SettingsViewController.m b/matrixConsole/ViewController/SettingsViewController.m new file mode 100644 index 000000000..e1753b8a9 --- /dev/null +++ b/matrixConsole/ViewController/SettingsViewController.m @@ -0,0 +1,517 @@ +/* + Copyright 2014 OpenMarket 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 "SettingsViewController.h" + +#import "AppDelegate.h" +#import "AppSettings.h" +#import "MatrixHandler.h" +#import "MediaManager.h" + +#import "SettingsTableViewCell.h" + +#define SETTINGS_SECTION_NOTIFICATIONS_INDEX 0 +#define SETTINGS_SECTION_ROOMS_INDEX 1 +#define SETTINGS_SECTION_CONFIGURATION_INDEX 2 +#define SETTINGS_SECTION_COMMANDS_INDEX 3 + +NSString* const kConfigurationFormatText = @"Home server: %@\r\nIdentity server: %@\r\nUser ID: %@\r\nAccess token: %@"; +NSString* const kCommandsDescriptionText = @"The following commands are available in the room chat:\r\n\r\n /nick : change your display name\r\n /me : send the action you are doing. /me will be replaced by your display name\r\n /join : join a room\r\n /kick []: kick the user\r\n /ban []: ban the user\r\n /unban : unban the user\r\n /op : set user power level\r\n /deop : reset user power level to the room default value"; + +@interface SettingsViewController () { + id imageLoader; + + NSString *currentDisplayName; + NSString *currentPictureURL; + NSString *uploadedPictureURL; + + NSMutableArray *errorAlerts; + + UIButton *logoutBtn; + UISwitch *notificationsSwitch; + UISwitch *allEventsSwitch; + UISwitch *unsupportedMsgSwitch; + UISwitch *sortMembersSwitch; +} +@property (strong, nonatomic) IBOutlet UITableView *tableView; +@property (weak, nonatomic) IBOutlet UIView *tableHeader; +@property (weak, nonatomic) IBOutlet UIButton *userPicture; +@property (weak, nonatomic) IBOutlet UITextField *userDisplayName; +@property (strong, nonatomic) IBOutlet UIActivityIndicatorView *activityIndicator; + +- (IBAction)onButtonPressed:(id)sender; + +@end + +@implementation SettingsViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + // Do any additional setup after loading the view, typically from a nib. + + // Add logout button in nav bar + logoutBtn = [UIButton buttonWithType:UIButtonTypeSystem]; + logoutBtn.frame = CGRectMake(0, 0, 60, 44); + [logoutBtn setTitle:@"Logout" forState:UIControlStateNormal]; + [logoutBtn setTitle:@"Logout" forState:UIControlStateHighlighted]; + [logoutBtn addTarget:self action:@selector(onButtonPressed:) forControlEvents:UIControlEventTouchUpInside]; + self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:logoutBtn]; + + errorAlerts = [NSMutableArray array]; + + [self startViewConfiguration]; +} + +- (void)didReceiveMemoryWarning { + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. + + if (imageLoader) { + [MediaManager cancel:imageLoader]; + imageLoader = nil; + } +} + +- (void)dealloc { + [[MatrixHandler sharedHandler] removeObserver:self forKeyPath:@"userDisplayName"]; + [[MatrixHandler sharedHandler] removeObserver:self forKeyPath:@"userPictureURL"]; + + // Cancel picture loader (if any) + if (imageLoader) { + [MediaManager cancel:imageLoader]; + imageLoader = nil; + } + + // Cancel potential error alerts + for (CustomAlert *alert in errorAlerts){ + [alert dismiss:NO]; + } + errorAlerts = nil; + + logoutBtn = nil; + notificationsSwitch = nil; + allEventsSwitch = nil; + unsupportedMsgSwitch = nil; + sortMembersSwitch = nil; +} + +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + // Refresh displayed settings + [self.tableView reloadData]; +} + +- (void)viewWillDisappear:(BOOL)animated { + [super viewWillDisappear:animated]; +} + +#pragma mark - Internal methods + +- (void)reset { + // Cancel picture loader (if any) + if (imageLoader) { + [MediaManager cancel:imageLoader]; + imageLoader = nil; + } + + // Cancel potential error alerts + for (CustomAlert *alert in errorAlerts){ + [alert dismiss:NO]; + } + + currentPictureURL = nil; + uploadedPictureURL = nil; + UIImage *image = [UIImage imageNamed:@"default-profile"]; + [self.userPicture setImage:image forState:UIControlStateNormal]; + [self.userPicture setImage:image forState:UIControlStateHighlighted]; + + currentDisplayName = nil; + self.userDisplayName.text = nil; +} + +- (void)startViewConfiguration { + // Initialize + [self reset]; + + // Set current user's information and add observers + MatrixHandler *mxHandler = [MatrixHandler sharedHandler]; + [_activityIndicator startAnimating]; + // Disable user's interactions + _userPicture.enabled = NO; + _userDisplayName.enabled = NO; + + // Set user's display name + currentDisplayName = mxHandler.userDisplayName; + self.userDisplayName.text = mxHandler.userDisplayName; + [[MatrixHandler sharedHandler] addObserver:self forKeyPath:@"userDisplayName" options:0 context:nil]; + [mxHandler.mxRestClient displayNameForUser:mxHandler.userId success:^(NSString *displayname) { + mxHandler.userDisplayName = displayname; + + // Set user's picture url + [self updateUserPicture:mxHandler.userPictureURL]; + [[MatrixHandler sharedHandler] addObserver:self forKeyPath:@"userPictureURL" options:0 context:nil]; + [mxHandler.mxRestClient avatarUrlForUser:mxHandler.userId success:^(NSString *avatar_url) { + mxHandler.userPictureURL = avatar_url; + [self endViewConfiguration]; + + } failure:^(NSError *error) { + NSLog(@"Get picture url failed: %@", error); + //Alert user + [[AppDelegate theDelegate] showErrorAsAlert:error]; + [self endViewConfiguration]; + }]; + } failure:^(NSError *error) { + NSLog(@"Get displayName failed: %@", error); + //Alert user + [[AppDelegate theDelegate] showErrorAsAlert:error]; + [self endViewConfiguration]; + }]; +} + +- (void)endViewConfiguration { + [_activityIndicator stopAnimating]; + + _userPicture.enabled = YES; + _userDisplayName.enabled = YES; + + [self.tableView reloadData]; +} + +- (void)saveDisplayName { + // Check whether the display name has been changed + NSString *displayname = self.userDisplayName.text; + if ([displayname isEqualToString:currentDisplayName] == NO) { + // Save display name + [_activityIndicator startAnimating]; + _userDisplayName.enabled = NO; + + MatrixHandler *mxHandler = [MatrixHandler sharedHandler]; + [mxHandler.mxRestClient setDisplayName:displayname success:^{ + currentDisplayName = displayname; + + [_activityIndicator stopAnimating]; + _userDisplayName.enabled = YES; + } failure:^(NSError *error) { + NSLog(@"Set displayName failed: %@", error); + [_activityIndicator stopAnimating]; + _userDisplayName.enabled = YES; + + //Alert user + NSString *title = [error.userInfo valueForKey:NSLocalizedFailureReasonErrorKey]; + if (!title) { + title = @"Display name change failed"; + } + NSString *msg = [error.userInfo valueForKey:NSLocalizedDescriptionKey]; + + CustomAlert *alert = [[CustomAlert alloc] initWithTitle:title message:msg style:CustomAlertStyleAlert]; + [errorAlerts addObject:alert]; + alert.cancelButtonIndex = [alert addActionWithTitle:@"Cancel" style:CustomAlertActionStyleDefault handler:^(CustomAlert *alert) { + [errorAlerts removeObject:alert]; + // Remove change + self.userDisplayName.text = currentDisplayName; + }]; + [alert addActionWithTitle:@"Retry" style:CustomAlertActionStyleDefault handler:^(CustomAlert *alert) { + [errorAlerts removeObject:alert]; + [self saveDisplayName]; + }]; + [alert showInViewController:self]; + }]; + } +} + +- (void)savePicture { + MatrixHandler *mxHandler = [MatrixHandler sharedHandler]; + + // Save picture + [_activityIndicator startAnimating]; + _userPicture.enabled = NO; + + if (uploadedPictureURL == nil) { + // Upload picture + [mxHandler.mxRestClient uploadContent:UIImageJPEGRepresentation([self.userPicture imageForState:UIControlStateNormal], 0.5) + mimeType:@"image/jpeg" + timeout:30 + success:^(NSString *url) { + // Store uploaded picture url and trigger picture saving + uploadedPictureURL = url; + [self savePicture]; + } failure:^(NSError *error) { + NSLog(@"Upload image failed: %@", error); + [_activityIndicator stopAnimating]; + _userPicture.enabled = YES; + [self handleErrorDuringPictureSaving:error]; + }]; + } else { + [mxHandler.mxRestClient setAvatarUrl:uploadedPictureURL + success:^{ + [MatrixHandler sharedHandler].userPictureURL = uploadedPictureURL; + uploadedPictureURL = nil; + + [_activityIndicator stopAnimating]; + _userPicture.enabled = YES; + } failure:^(NSError *error) { + NSLog(@"Set avatar url failed: %@", error); + [_activityIndicator stopAnimating]; + _userPicture.enabled = YES; + [self handleErrorDuringPictureSaving:error]; + }]; + } +} + +- (void)handleErrorDuringPictureSaving:(NSError*)error { + NSString *title = [error.userInfo valueForKey:NSLocalizedFailureReasonErrorKey]; + if (!title) { + title = @"Picture change failed"; + } + NSString *msg = [error.userInfo valueForKey:NSLocalizedDescriptionKey]; + + CustomAlert *alert = [[CustomAlert alloc] initWithTitle:title message:msg style:CustomAlertStyleAlert]; + [errorAlerts addObject:alert]; + alert.cancelButtonIndex = [alert addActionWithTitle:@"Cancel" style:CustomAlertActionStyleDefault handler:^(CustomAlert *alert) { + [errorAlerts removeObject:alert]; + // Remove change + uploadedPictureURL = nil; + [self updateUserPicture:[MatrixHandler sharedHandler].userPictureURL]; + }]; + [alert addActionWithTitle:@"Retry" style:CustomAlertActionStyleDefault handler:^(CustomAlert *alert) { + [errorAlerts removeObject:alert]; + [self savePicture]; + }]; + + [alert showInViewController:self]; +} + +- (void)updateUserPicture:(NSString *)avatar_url { + if (currentPictureURL == nil || [currentPictureURL isEqualToString:avatar_url] == NO) { + // Cancel previous loader (if any) + if (imageLoader) { + [MediaManager cancel:imageLoader]; + imageLoader = nil; + } + + currentPictureURL = [avatar_url isEqual:[NSNull null]] ? nil : avatar_url; + if (currentPictureURL) { + // Load user's picture + imageLoader = [MediaManager loadPicture:currentPictureURL success:^(UIImage *image) { + [self.userPicture setImage:image forState:UIControlStateNormal]; + [self.userPicture setImage:image forState:UIControlStateHighlighted]; + } failure:^(NSError *error) { + // Reset picture URL in order to try next time + currentPictureURL = nil; + }]; + } else { + // Set placeholder + UIImage *image = [UIImage imageNamed:@"default-profile"]; + [self.userPicture setImage:image forState:UIControlStateNormal]; + [self.userPicture setImage:image forState:UIControlStateHighlighted]; + } + } +} + +#pragma mark - KVO + +- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { + if ([@"userDisplayName" isEqualToString:keyPath]) { + // Refresh user's display name + MatrixHandler *mxHandler = [MatrixHandler sharedHandler]; + if ([currentDisplayName isEqualToString:mxHandler.userDisplayName] == NO) { + currentDisplayName = mxHandler.userDisplayName; + self.userDisplayName.text = mxHandler.userDisplayName; + } + } else if ([@"userPictureURL" isEqualToString:keyPath]) { + // Refresh user's picture + MatrixHandler *mxHandler = [MatrixHandler sharedHandler]; + [self updateUserPicture:mxHandler.userPictureURL]; + } +} + +#pragma mark - Actions + +- (IBAction)onButtonPressed:(id)sender { + [self dismissKeyboard]; + + if (sender == _userPicture) { + // Open picture gallery + UIImagePickerController *mediaPicker = [[UIImagePickerController alloc] init]; + mediaPicker.delegate = self; + mediaPicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary; + mediaPicker.allowsEditing = NO; + [[AppDelegate theDelegate].masterTabBarController presentMediaPicker:mediaPicker]; + } else if (sender == logoutBtn) { + [self reset]; + [[AppDelegate theDelegate] logout]; + } else if (sender == notificationsSwitch) { + [AppSettings sharedSettings].enableNotifications = notificationsSwitch.on; + } else if (sender == allEventsSwitch) { + [AppSettings sharedSettings].displayAllEvents = allEventsSwitch.on; + } else if (sender == unsupportedMsgSwitch) { + [AppSettings sharedSettings].hideUnsupportedMessages = unsupportedMsgSwitch.on; + } else if (sender == sortMembersSwitch) { + [AppSettings sharedSettings].sortMembersUsingLastSeenTime = sortMembersSwitch.on; + } +} + +#pragma mark - keyboard + +- (void)dismissKeyboard +{ + // Hide the keyboard + [_userDisplayName resignFirstResponder]; + // Save display name change (if any) + [self saveDisplayName]; +} + +#pragma mark - UITextField delegate + +- (BOOL)textFieldShouldReturn:(UITextField*) textField +{ + // "Done" key has been pressed + [self dismissKeyboard]; + return YES; +} + +#pragma mark - Table view data source + +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { + return 4; +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + if (section == SETTINGS_SECTION_NOTIFICATIONS_INDEX) { + return 1; + } else if (section == SETTINGS_SECTION_ROOMS_INDEX) { + return 3; + } else if (section == SETTINGS_SECTION_CONFIGURATION_INDEX) { + return 1; + } else if (section == SETTINGS_SECTION_COMMANDS_INDEX) { + return 1; + } + + return 0; +} + +- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { + if (indexPath.section == SETTINGS_SECTION_NOTIFICATIONS_INDEX) { + return 44; + } else if (indexPath.section == SETTINGS_SECTION_ROOMS_INDEX) { + return 44; + } else if (indexPath.section == SETTINGS_SECTION_CONFIGURATION_INDEX) { + UITextView *textView = [[UITextView alloc] initWithFrame:CGRectMake(0, 0, tableView.frame.size.width, MAXFLOAT)]; + textView.font = [UIFont systemFontOfSize:14]; + MatrixHandler *mxHandler = [MatrixHandler sharedHandler]; + textView.text = [NSString stringWithFormat:kConfigurationFormatText, mxHandler.homeServerURL, nil, mxHandler.userId, mxHandler.accessToken]; + CGSize contentSize = [textView sizeThatFits:textView.frame.size]; + return contentSize.height + 1; + } else if (indexPath.section == SETTINGS_SECTION_COMMANDS_INDEX) { + UITextView *textView = [[UITextView alloc] initWithFrame:CGRectMake(0, 0, tableView.frame.size.width, MAXFLOAT)]; + textView.font = [UIFont systemFontOfSize:14]; + textView.text = kCommandsDescriptionText; + CGSize contentSize = [textView sizeThatFits:textView.frame.size]; + return contentSize.height + 1; + } + + return 44; +} + +- (CGFloat) tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section +{ + return 30; +} +- (CGFloat) tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section +{ + return 1; +} + +- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section +{ + UILabel *sectionHeader = [[UILabel alloc] initWithFrame:[tableView rectForHeaderInSection:section]]; + sectionHeader.font = [UIFont boldSystemFontOfSize:16]; + sectionHeader.backgroundColor = [UIColor colorWithRed:0.9 green:0.9 blue:0.9 alpha:1.0]; + + if (section == SETTINGS_SECTION_NOTIFICATIONS_INDEX) { + sectionHeader.text = @" Notifications"; + } else if (section == SETTINGS_SECTION_ROOMS_INDEX) { + sectionHeader.text = @" Rooms"; + } else if (section == SETTINGS_SECTION_CONFIGURATION_INDEX) { + sectionHeader.text = @" Configuration"; + } else if (section == SETTINGS_SECTION_COMMANDS_INDEX) { + sectionHeader.text = @" Commands"; + } else { + sectionHeader = nil; + } + return sectionHeader; +} + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { + SettingsTableViewCell *cell = nil; + + if (indexPath.section == SETTINGS_SECTION_NOTIFICATIONS_INDEX) { + SettingsTableCellWithSwitch *notificationsCell = [tableView dequeueReusableCellWithIdentifier:@"SettingsCellWithSwitch" forIndexPath:indexPath]; + notificationsCell.settingLabel.text = @"Enable notifications"; + notificationsCell.settingSwitch.on = [[AppSettings sharedSettings] enableNotifications]; + notificationsSwitch = notificationsCell.settingSwitch; + cell = notificationsCell; + } else if (indexPath.section == SETTINGS_SECTION_ROOMS_INDEX) { + SettingsTableCellWithSwitch *roomsSettingCell = [tableView dequeueReusableCellWithIdentifier:@"SettingsCellWithSwitch" forIndexPath:indexPath]; + if (indexPath.row == 0) { + roomsSettingCell.settingLabel.text = @"Display all events"; + roomsSettingCell.settingSwitch.on = [[AppSettings sharedSettings] displayAllEvents]; + allEventsSwitch = roomsSettingCell.settingSwitch; + } else if (indexPath.row == 1) { + roomsSettingCell.settingLabel.text = @"Hide unsupported messages"; + roomsSettingCell.settingSwitch.on = [[AppSettings sharedSettings] hideUnsupportedMessages]; + unsupportedMsgSwitch = roomsSettingCell.settingSwitch; + } else { + roomsSettingCell.settingLabel.text = @"Sort members by last seen time"; + roomsSettingCell.settingSwitch.on = [[AppSettings sharedSettings] sortMembersUsingLastSeenTime]; + sortMembersSwitch = roomsSettingCell.settingSwitch; + } + cell = roomsSettingCell; + } else if (indexPath.section == SETTINGS_SECTION_CONFIGURATION_INDEX) { + SettingsTableCellWithTextView *configCell = [tableView dequeueReusableCellWithIdentifier:@"SettingsCellWithTextView" forIndexPath:indexPath]; + MatrixHandler *mxHandler = [MatrixHandler sharedHandler]; + configCell.settingTextView.text = [NSString stringWithFormat:kConfigurationFormatText, mxHandler.homeServerURL, nil, mxHandler.userId, mxHandler.accessToken]; + cell = configCell; + } else if (indexPath.section == SETTINGS_SECTION_COMMANDS_INDEX) { + SettingsTableCellWithTextView *commandsCell = [tableView dequeueReusableCellWithIdentifier:@"SettingsCellWithTextView" forIndexPath:indexPath]; + commandsCell.settingTextView.text = kCommandsDescriptionText; + cell = commandsCell; + } + + return cell; +} + +# pragma mark - UIImagePickerControllerDelegate + +- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info { + UIImage *selectedImage = [info objectForKey:UIImagePickerControllerOriginalImage]; + if (selectedImage) { + [self.userPicture setImage:selectedImage forState:UIControlStateNormal]; + [self.userPicture setImage:selectedImage forState:UIControlStateHighlighted]; + [self savePicture]; + } + [self dismissMediaPicker]; +} + +- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker { + [self dismissMediaPicker]; +} + +- (void)dismissMediaPicker { + [[AppDelegate theDelegate].masterTabBarController dismissMediaPicker]; +} + +@end diff --git a/matrixConsole/main.m b/matrixConsole/main.m new file mode 100644 index 000000000..2e3f4608c --- /dev/null +++ b/matrixConsole/main.m @@ -0,0 +1,24 @@ +/* + Copyright 2014 OpenMarket 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 +#import "AppDelegate.h" + +int main(int argc, char * argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} diff --git a/matrixConsoleTests/Info.plist b/matrixConsoleTests/Info.plist new file mode 100644 index 000000000..dab962b2d --- /dev/null +++ b/matrixConsoleTests/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + org.matrix.$(PRODUCT_NAME:rfc1034identifier) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/matrixConsoleTests/matrixConsoleTests.m b/matrixConsoleTests/matrixConsoleTests.m new file mode 100644 index 000000000..c7463668b --- /dev/null +++ b/matrixConsoleTests/matrixConsoleTests.m @@ -0,0 +1,48 @@ +/* + Copyright 2014 OpenMarket 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 +#import + +@interface syMessagingTests : XCTestCase + +@end + +@implementation syMessagingTests + +- (void)setUp { + [super setUp]; + // Put setup code here. This method is called before the invocation of each test method in the class. +} + +- (void)tearDown { + // Put teardown code here. This method is called after the invocation of each test method in the class. + [super tearDown]; +} + +- (void)testExample { + // This is an example of a functional test case. + XCTAssert(YES, @"Pass"); +} + +- (void)testPerformanceExample { + // This is an example of a performance test case. + [self measureBlock:^{ + // Put the code you want to measure the time of here. + }]; +} + +@end