Rename directories of sample sources (matrixConsole)

This commit is contained in:
giomfo 2014-11-24 10:38:23 +01:00
commit 6156cb0f78
87 changed files with 7854 additions and 0 deletions

29
.gitignore vendored Normal file
View file

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

16
Podfile Normal file
View file

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

42
Podfile.lock Normal file
View file

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

11
README.rst Normal file
View file

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

View file

@ -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 = "<group>"; };
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 = "<group>"; };
F00B5DB71A1B9BCE00EA1C8D /* CustomImageView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CustomImageView.h; sourceTree = "<group>"; };
F00B5DB81A1B9BCE00EA1C8D /* CustomImageView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CustomImageView.m; sourceTree = "<group>"; };
F01628BC19E29C660071C473 /* default-profile.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "default-profile.png"; sourceTree = "<group>"; };
F01628BE19E29C660071C473 /* logo.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = logo.png; sourceTree = "<group>"; };
F024098119E7D177006E741B /* tab_recents@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "tab_recents@2x.png"; sourceTree = "<group>"; };
F02BCE221A1A5A2B00543B47 /* play.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = play.png; sourceTree = "<group>"; };
F02D707419F1DC9E007B47D3 /* RoomMemberTableCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RoomMemberTableCell.h; sourceTree = "<group>"; };
F02D707519F1DC9E007B47D3 /* RoomMemberTableCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RoomMemberTableCell.m; sourceTree = "<group>"; };
F03C470F1A02952800E445AB /* CustomAlert.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CustomAlert.h; sourceTree = "<group>"; };
F03C47101A02952800E445AB /* CustomAlert.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CustomAlert.m; sourceTree = "<group>"; };
F03EF5EA19F171EB00A0EE52 /* HomeViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HomeViewController.h; sourceTree = "<group>"; };
F03EF5EB19F171EB00A0EE52 /* HomeViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HomeViewController.m; sourceTree = "<group>"; };
F03EF5EC19F171EB00A0EE52 /* LoginViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LoginViewController.h; sourceTree = "<group>"; };
F03EF5ED19F171EB00A0EE52 /* LoginViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LoginViewController.m; sourceTree = "<group>"; };
F03EF5EE19F171EB00A0EE52 /* MasterTabBarController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MasterTabBarController.h; sourceTree = "<group>"; };
F03EF5EF19F171EB00A0EE52 /* MasterTabBarController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MasterTabBarController.m; sourceTree = "<group>"; };
F03EF5F019F171EB00A0EE52 /* RecentsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RecentsViewController.h; sourceTree = "<group>"; };
F03EF5F119F171EB00A0EE52 /* RecentsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RecentsViewController.m; sourceTree = "<group>"; };
F03EF5F219F171EB00A0EE52 /* RoomViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RoomViewController.h; sourceTree = "<group>"; };
F03EF5F319F171EB00A0EE52 /* RoomViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RoomViewController.m; sourceTree = "<group>"; };
F03EF5F419F171EB00A0EE52 /* SettingsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SettingsViewController.h; sourceTree = "<group>"; };
F03EF5F519F171EB00A0EE52 /* SettingsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SettingsViewController.m; sourceTree = "<group>"; };
F03EF5FD19F1762000A0EE52 /* RoomMessageTableCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RoomMessageTableCell.h; sourceTree = "<group>"; };
F03EF5FE19F1762000A0EE52 /* RoomMessageTableCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RoomMessageTableCell.m; sourceTree = "<group>"; };
F03EF60019F19E7C00A0EE52 /* MediaManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MediaManager.h; sourceTree = "<group>"; };
F03EF60119F19E7C00A0EE52 /* MediaManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MediaManager.m; sourceTree = "<group>"; };
F05B955D19DEED8A008761B0 /* MatrixHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MatrixHandler.h; sourceTree = "<group>"; };
F05B955E19DEED8A008761B0 /* MatrixHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MatrixHandler.m; sourceTree = "<group>"; };
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 = "<group>"; };
F07A80D719DD9DE700B621A1 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
F07A80D919DD9DE700B621A1 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
F07A80DA19DD9DE700B621A1 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
F07A80E319DD9DE700B621A1 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
F07A80E519DD9DE700B621A1 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
F07A80E819DD9DE700B621A1 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = "<group>"; };
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 = "<group>"; };
F07A80F419DD9DE700B621A1 /* syMessagingTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = syMessagingTests.m; sourceTree = "<group>"; };
F08B6FCB1A1DE7F80094A35B /* matrixConsole.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = matrixConsole.jpg; sourceTree = "<group>"; };
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 = "<group>"; };
F0CEA5AD19E6895E00E47915 /* tab_recents.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = tab_recents.png; sourceTree = "<group>"; };
F0CEA5B019E6898800E47915 /* tab_home.ico */ = {isa = PBXFileReference; lastKnownFileType = image.ico; path = tab_home.ico; sourceTree = "<group>"; };
F0D3C30A1A011EF10000D49E /* AppSettings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppSettings.h; sourceTree = "<group>"; };
F0D3C30B1A011EF10000D49E /* AppSettings.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppSettings.m; sourceTree = "<group>"; };
F0D3C30D1A01330F0000D49E /* SettingsTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SettingsTableViewCell.h; sourceTree = "<group>"; };
F0D3C30E1A01330F0000D49E /* SettingsTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SettingsTableViewCell.m; sourceTree = "<group>"; };
F0E84D3E1A1F9AEC005F2E42 /* RecentsTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RecentsTableViewCell.h; sourceTree = "<group>"; };
F0E84D3F1A1F9AEC005F2E42 /* RecentsTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RecentsTableViewCell.m; sourceTree = "<group>"; };
/* 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 = "<group>";
};
EAA71E3C2B16D1D86B3F5100 /* Frameworks */ = {
isa = PBXGroup;
children = (
F08DCBDA1A093BFA008C65B6 /* MobileCoreServices.framework */,
8141B1E2401FFCC3C5B99234 /* libPods-matrixConsole.a */,
);
name = Frameworks;
sourceTree = "<group>";
};
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 = "<group>";
};
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 = "<group>";
};
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 = "<group>";
};
F07A80C919DD9DE700B621A1 = {
isa = PBXGroup;
children = (
F07A80D419DD9DE700B621A1 /* syMessaging */,
F07A80F119DD9DE700B621A1 /* syMessagingTests */,
F07A80D319DD9DE700B621A1 /* Products */,
B18A10A9FB884DD357EBD414 /* Pods */,
EAA71E3C2B16D1D86B3F5100 /* Frameworks */,
);
sourceTree = "<group>";
};
F07A80D319DD9DE700B621A1 /* Products */ = {
isa = PBXGroup;
children = (
F07A80D219DD9DE700B621A1 /* matrixConsole.app */,
F07A80EE19DD9DE700B621A1 /* matrixConsoleTests.xctest */,
);
name = Products;
sourceTree = "<group>";
};
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 = "<group>";
};
F07A80D519DD9DE700B621A1 /* Supporting Files */ = {
isa = PBXGroup;
children = (
F07A80D619DD9DE700B621A1 /* Info.plist */,
F07A80D719DD9DE700B621A1 /* main.m */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
F07A80F119DD9DE700B621A1 /* syMessagingTests */ = {
isa = PBXGroup;
children = (
F07A80F419DD9DE700B621A1 /* syMessagingTests.m */,
F07A80F219DD9DE700B621A1 /* Supporting Files */,
);
path = syMessagingTests;
sourceTree = "<group>";
};
F07A80F219DD9DE700B621A1 /* Supporting Files */ = {
isa = PBXGroup;
children = (
F07A80F319DD9DE700B621A1 /* Info.plist */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
/* 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 = "<group>";
};
F07A80E719DD9DE700B621A1 /* LaunchScreen.xib */ = {
isa = PBXVariantGroup;
children = (
F07A80E819DD9DE700B621A1 /* Base */,
);
name = LaunchScreen.xib;
sourceTree = "<group>";
};
/* 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 */;
}

View file

@ -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 <UIKit/UIKit.h>
#import "MasterTabBarController.h"
#import "CustomAlert.h"
@interface AppDelegate : UIResponder <UIApplicationDelegate, UITabBarControllerDelegate>
@property (strong, nonatomic) UIWindow *window;
@property (strong, nonatomic) MasterTabBarController *masterTabBarController;
@property (strong, nonatomic) CustomAlert *errorNotification;
+ (AppDelegate*)theDelegate;
- (void)logout;
- (CustomAlert*)showErrorAsAlert:(NSError*)error;
@end

133
matrixConsole/AppDelegate.m Normal file
View file

@ -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 () <UISplitViewControllerDelegate>
@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

View file

@ -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 <UIKit/UIKit.h>
@interface AppSettings : NSObject
@property (nonatomic) BOOL enableNotifications;
@property (nonatomic) BOOL displayAllEvents;
@property (nonatomic) BOOL hideUnsupportedMessages;
@property (nonatomic) BOOL sortMembersUsingLastSeenTime;
+ (AppSettings *)sharedSettings;
- (void)reset;
@end

View file

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 397 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 194 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 910 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
matrixConsole/Assets/play.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 198 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

View file

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="6250" systemVersion="13F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6244"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB">
<rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="matrixConsole.jpg" translatesAutoresizingMaskIntoConstraints="NO" id="Aaa-NS-PsE">
<rect key="frame" x="120" y="150" width="240" height="128"/>
<constraints>
<constraint firstAttribute="height" constant="128" id="1ye-KY-Dhp"/>
<constraint firstAttribute="width" constant="240" id="Ar8-en-VzW"/>
</constraints>
</imageView>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
<constraints>
<constraint firstItem="Aaa-NS-PsE" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" constant="150" id="8Ty-H4-BZ5"/>
<constraint firstAttribute="centerX" secondItem="Aaa-NS-PsE" secondAttribute="centerX" id="JqN-6c-hL6"/>
</constraints>
<nil key="simulatedStatusBarMetrics"/>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<point key="canvasLocation" x="548" y="455"/>
</view>
</objects>
<resources>
<image name="matrixConsole.jpg" width="500" height="230"/>
</resources>
</document>

File diff suppressed because it is too large Load diff

View file

@ -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 <UIKit/UIKit.h>
// 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 <UIActionSheetDelegate> {
}
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

210
matrixConsole/CustomAlert.m Normal file
View file

@ -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 <objc/runtime.h>
@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

View file

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

View file

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

57
matrixConsole/Info.plist Normal file
View file

@ -0,0 +1,57 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>org.matrix.$(PRODUCT_NAME:rfc1034identifier)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UIStatusBarTintParameters</key>
<dict>
<key>UINavigationBar</key>
<dict>
<key>Style</key>
<string>UIBarStyleDefault</string>
<key>Translucent</key>
<false/>
</dict>
</dict>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>

View file

@ -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 <MatrixSDK/MatrixSDK.h>
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

View file

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

View file

@ -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 <AVFoundation/AVFoundation.h>
#import <UIKit/UIKit.h>
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

View file

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

View file

@ -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 <UIKit/UIKit.h>
// 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

View file

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

View file

@ -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 <UIKit/UIKit.h>
@interface RecentsTableViewCell : UITableViewCell
@property (weak, nonatomic) IBOutlet UILabel *roomTitle;
@property (weak, nonatomic) IBOutlet UILabel *lastEventDescription;
@property (weak, nonatomic) IBOutlet UILabel *recentDate;
@end

View file

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

View file

@ -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 <UIKit/UIKit.h>
#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

View file

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

View file

@ -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 <UIKit/UIKit.h>
#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

View file

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

View file

@ -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 <UIKit/UIKit.h>
@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

View file

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

View file

@ -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 <UIKit/UIKit.h>
@interface HomeViewController : UITableViewController <UITextFieldDelegate>
@end

View file

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

View file

@ -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 <UIKit/UIKit.h>
@interface LoginViewController : UIViewController <UITextFieldDelegate>
@end

View file

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

View file

@ -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 <UIKit/UIKit.h>
#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

View file

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

View file

@ -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 <UIKit/UIKit.h>
@class RoomViewController;
@interface RecentsViewController : UITableViewController
@property (strong, nonatomic) NSString *preSelectedRoomId; // set a non-nil value to this property will open room details
@end

View file

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

View file

@ -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 <UIKit/UIKit.h>
@interface RoomViewController : UIViewController <UITableViewDataSource, UITableViewDelegate, UITextFieldDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate, UIGestureRecognizerDelegate>
@property (strong, nonatomic) NSString *roomId;
@end

File diff suppressed because it is too large Load diff

View file

@ -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 <UIKit/UIKit.h>
@interface SettingsViewController : UITableViewController <UITextFieldDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate>
- (void)reset;
@end

View file

@ -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 <display_name>: change your display name\r\n /me <action>: send the action you are doing. /me will be replaced by your display name\r\n /join <room_alias>: join a room\r\n /kick <user_id> [<reason>]: kick the user\r\n /ban <user_id> [<reason>]: ban the user\r\n /unban <user_id>: unban the user\r\n /op <user_id> <power_level>: set user power level\r\n /deop <user_id>: 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

24
matrixConsole/main.m Normal file
View file

@ -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 <UIKit/UIKit.h>
#import "AppDelegate.h"
int main(int argc, char * argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}

View file

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>org.matrix.$(PRODUCT_NAME:rfc1034identifier)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

View file

@ -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 <UIKit/UIKit.h>
#import <XCTest/XCTest.h>
@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