mirror of
https://gitlab.opencode.de/bwi/bundesmessenger/clients/bundesmessenger-ios.git
synced 2026-05-19 14:12:13 +02:00
replace matrixConsole project with Vector Xcode project.
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
Copyright 2015 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 <MessageUI/MessageUI.h>
|
||||
|
||||
#import <MatrixKit/MXKResponderRageShaking.h>
|
||||
|
||||
@interface RageShakeManager : NSObject <MXKResponderRageShaking, MFMailComposeViewControllerDelegate>
|
||||
|
||||
+ (id)sharedManager;
|
||||
|
||||
/**
|
||||
Prompt user to report a crash. The alert is presented by the provided view controller.
|
||||
|
||||
@param viewController the view controller which presents the alert
|
||||
*/
|
||||
- (void)promptCrashReportInViewController:(UIViewController*)viewController;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,260 @@
|
||||
/*
|
||||
Copyright 2015 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.
|
||||
*/
|
||||
|
||||
#define RAGESHAKEMANAGER_MINIMUM_SHAKING_DURATION 2
|
||||
|
||||
#import "RageShakeManager.h"
|
||||
|
||||
#import "AppDelegate.h"
|
||||
|
||||
#import "GBDeviceInfo_iOS.h"
|
||||
|
||||
#import "NSBundle+MatrixKit.h"
|
||||
|
||||
static RageShakeManager* sharedInstance = nil;
|
||||
|
||||
@interface RageShakeManager() {
|
||||
bool isShaking;
|
||||
double startShakingTimeStamp;
|
||||
|
||||
MXKAlert *confirmationAlert;
|
||||
|
||||
MFMailComposeViewController* mailComposer;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation RageShakeManager
|
||||
|
||||
#pragma mark Singleton Method
|
||||
|
||||
+ (id)sharedManager {
|
||||
@synchronized(self) {
|
||||
if(sharedInstance == nil)
|
||||
sharedInstance = [[self alloc] init];
|
||||
}
|
||||
return sharedInstance;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (instancetype)init {
|
||||
|
||||
self = [super init];
|
||||
if (self) {
|
||||
isShaking = NO;
|
||||
startShakingTimeStamp = 0;
|
||||
|
||||
mailComposer = nil;
|
||||
confirmationAlert = nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)promptCrashReportInViewController:(UIViewController*)viewController {
|
||||
if ([MXLogger crashLog] && [MFMailComposeViewController canSendMail]) {
|
||||
|
||||
confirmationAlert = [[MXKAlert alloc] initWithTitle:NSLocalizedStringFromTable(@"bug_report_prompt", @"MatrixConsole", nil) message:nil style:MXKAlertStyleAlert];
|
||||
|
||||
__weak typeof(self) weakSelf = self;
|
||||
[confirmationAlert addActionWithTitle:[NSBundle mxk_localizedStringForKey:@"cancel"] style:MXKAlertActionStyleDefault handler:^(MXKAlert *alert) {
|
||||
typeof(self) self = weakSelf;
|
||||
self->confirmationAlert = nil;
|
||||
|
||||
// Erase the crash log (there is only chance for the user to send it)
|
||||
[MXLogger deleteCrashLog];
|
||||
}];
|
||||
|
||||
[confirmationAlert addActionWithTitle:[NSBundle mxk_localizedStringForKey:@"ok"] style:MXKAlertActionStyleDefault handler:^(MXKAlert *alert) {
|
||||
typeof(self) self = weakSelf;
|
||||
self->confirmationAlert = nil;
|
||||
|
||||
[self sendEmail:viewController withSnapshot:NO];
|
||||
}];
|
||||
|
||||
[confirmationAlert showInViewController:viewController];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - MXKResponderRageShaking
|
||||
|
||||
- (void)startShaking:(UIResponder*)responder {
|
||||
|
||||
// Start only if the application is in foreground
|
||||
if ([AppDelegate theDelegate].isAppForeground && !confirmationAlert) {
|
||||
NSLog(@"[RageShakeManager] Start shaking with [%@]", [responder class]);
|
||||
|
||||
startShakingTimeStamp = [[NSDate date] timeIntervalSince1970];
|
||||
isShaking = YES;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)stopShaking:(UIResponder*)responder {
|
||||
|
||||
NSLog(@"[RageShakeManager] Stop shaking with [%@]", [responder class]);
|
||||
|
||||
if (isShaking && [AppDelegate theDelegate].isAppForeground && !confirmationAlert
|
||||
&& (([[NSDate date] timeIntervalSince1970] - startShakingTimeStamp) > RAGESHAKEMANAGER_MINIMUM_SHAKING_DURATION)) {
|
||||
|
||||
if ([responder isKindOfClass:[UIViewController class]] && [MFMailComposeViewController canSendMail]) {
|
||||
confirmationAlert = [[MXKAlert alloc] initWithTitle:NSLocalizedStringFromTable(@"rage_shake_prompt", @"MatrixConsole", nil) message:nil style:MXKAlertStyleAlert];
|
||||
|
||||
__weak typeof(self) weakSelf = self;
|
||||
[confirmationAlert addActionWithTitle:[NSBundle mxk_localizedStringForKey:@"cancel"] style:MXKAlertActionStyleDefault handler:^(MXKAlert *alert) {
|
||||
typeof(self) self = weakSelf;
|
||||
self->confirmationAlert = nil;
|
||||
}];
|
||||
|
||||
[confirmationAlert addActionWithTitle:[NSBundle mxk_localizedStringForKey:@"ok"] style:MXKAlertActionStyleDefault handler:^(MXKAlert *alert) {
|
||||
typeof(self) self = weakSelf;
|
||||
self->confirmationAlert = nil;
|
||||
[self sendEmail:(UIViewController*)responder withSnapshot:YES];
|
||||
}];
|
||||
|
||||
[confirmationAlert showInViewController:(UIViewController*)responder];
|
||||
}
|
||||
}
|
||||
|
||||
isShaking = NO;
|
||||
}
|
||||
|
||||
- (void)cancel:(UIResponder*)responder {
|
||||
|
||||
isShaking = NO;
|
||||
}
|
||||
|
||||
/**
|
||||
Prepare and send a report email. The mail composer is presented by the provided view controller.
|
||||
|
||||
@param controller the view controller which presents the alert.
|
||||
@param snapshot if this boolean value is YES, a screenshot of `controller` is sent as email attachment
|
||||
*/
|
||||
- (void)sendEmail:(UIViewController*)controller withSnapshot:(BOOL)snapshot {
|
||||
|
||||
UIImage *image;
|
||||
|
||||
if (snapshot) {
|
||||
AppDelegate* theDelegate = [AppDelegate theDelegate];
|
||||
UIGraphicsBeginImageContextWithOptions(theDelegate.window.bounds.size, NO, [UIScreen mainScreen].scale);
|
||||
|
||||
// Iterate over every window from back to front
|
||||
for (UIWindow *window in [[UIApplication sharedApplication] windows])
|
||||
{
|
||||
if (![window respondsToSelector:@selector(screen)] || [window screen] == [UIScreen mainScreen])
|
||||
{
|
||||
// -renderInContext: renders in the coordinate space of the layer,
|
||||
// so we must first apply the layer's geometry to the graphics context
|
||||
CGContextSaveGState(UIGraphicsGetCurrentContext());
|
||||
// Center the context around the window's anchor point
|
||||
CGContextTranslateCTM(UIGraphicsGetCurrentContext(), [window center].x, [window center].y);
|
||||
// Apply the window's transform about the anchor point
|
||||
CGContextConcatCTM(UIGraphicsGetCurrentContext(), [window transform]);
|
||||
// Offset by the portion of the bounds left of and above the anchor point
|
||||
CGContextTranslateCTM(UIGraphicsGetCurrentContext(),
|
||||
-[window bounds].size.width * [[window layer] anchorPoint].x,
|
||||
-[window bounds].size.height * [[window layer] anchorPoint].y);
|
||||
|
||||
// Render the layer hierarchy to the current context
|
||||
[[window layer] renderInContext:UIGraphicsGetCurrentContext()];
|
||||
|
||||
// Restore the context
|
||||
CGContextRestoreGState(UIGraphicsGetCurrentContext());
|
||||
}
|
||||
}
|
||||
image = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
|
||||
// the image is copied in the clipboard
|
||||
[UIPasteboard generalPasteboard].image = image;
|
||||
}
|
||||
|
||||
if (controller) {
|
||||
mailComposer = [[MFMailComposeViewController alloc] init];
|
||||
|
||||
if ([MXLogger crashLog]) {
|
||||
[mailComposer setSubject:@"Matrix crash report"];
|
||||
}
|
||||
else {
|
||||
[mailComposer setSubject:@"Matrix bug report"];
|
||||
}
|
||||
|
||||
[mailComposer setToRecipients:[NSArray arrayWithObject:@"rageshake@matrix.org"]];
|
||||
|
||||
NSString* appVersion = [AppDelegate theDelegate].appVersion;
|
||||
NSString* build = [AppDelegate theDelegate].build;
|
||||
|
||||
NSMutableString* message = [[NSMutableString alloc] init];
|
||||
|
||||
[message appendFormat:@"Something went wrong on my Matrix client: \n\n\n"];
|
||||
|
||||
[message appendFormat:@"-----> my comments <-----\n\n\n"];
|
||||
|
||||
[message appendFormat:@"------------------------------\n"];
|
||||
[message appendFormat:@"Account info\n"];
|
||||
|
||||
NSArray *mxAccounts = [MXKAccountManager sharedManager].accounts;
|
||||
for (MXKAccount* account in mxAccounts) {
|
||||
NSString *disabled = account.disabled ? @" (disabled)" : @"";
|
||||
|
||||
[message appendFormat:@"userId: %@%@\n", account.mxCredentials.userId, disabled];
|
||||
[message appendFormat:@"displayname: %@\n", account.mxSession.myUser.displayname];
|
||||
[message appendFormat:@"homeServerURL: %@\n", account.mxCredentials.homeServer];
|
||||
}
|
||||
|
||||
[message appendFormat:@"------------------------------\n"];
|
||||
[message appendFormat:@"Application info\n"];
|
||||
[message appendFormat:@"Console version: %@\n", appVersion];
|
||||
[message appendFormat:@"MatrixKit version: %@\n", MatrixKitVersion];
|
||||
[message appendFormat:@"MatrixSDK version: %@\n", MatrixSDKVersion];
|
||||
if (build.length) {
|
||||
[message appendFormat:@"Build: %@\n", build];
|
||||
}
|
||||
[message appendFormat:@"------------------------------\n"];
|
||||
[message appendFormat:@"Device info\n"];
|
||||
[message appendFormat:@"model: %@\n", [GBDeviceInfo deviceDetails].modelString];
|
||||
[message appendFormat:@"operatingSystem: %@ %@\n", [[UIDevice currentDevice] systemName], [[UIDevice currentDevice] systemVersion]];
|
||||
|
||||
[mailComposer setMessageBody:message isHTML:NO];
|
||||
|
||||
// Attach image only if required
|
||||
if (image) {
|
||||
[mailComposer addAttachmentData:UIImageJPEGRepresentation(image, 1.0) mimeType:@"image/jpg" fileName:@"screenshot.jpg"];
|
||||
}
|
||||
|
||||
// Add logs files
|
||||
NSMutableArray *logFiles = [NSMutableArray arrayWithArray:[MXLogger logFiles]];
|
||||
if ([MXLogger crashLog]) {
|
||||
[logFiles addObject:[MXLogger crashLog]];
|
||||
}
|
||||
for (NSString *logFile in logFiles) {
|
||||
NSData *logContent = [NSData dataWithContentsOfFile:logFile];
|
||||
[mailComposer addAttachmentData:logContent mimeType:@"text/plain" fileName:[logFile lastPathComponent]];
|
||||
}
|
||||
mailComposer.mailComposeDelegate = self;
|
||||
[controller presentViewController:mailComposer animated:YES completion:nil];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - MFMailComposeViewControllerDelegate delegate
|
||||
|
||||
- (void)mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error {
|
||||
// Do not send this crash anymore
|
||||
[MXLogger deleteCrashLog];
|
||||
|
||||
[controller dismissViewControllerAnimated:NO completion:nil];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
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 <MatrixKit/MatrixKit.h>
|
||||
|
||||
#import "MasterTabBarController.h"
|
||||
|
||||
@interface AppDelegate : UIResponder <UIApplicationDelegate, UITabBarControllerDelegate, MXKCallViewControllerDelegate, MXKContactDetailsViewControllerDelegate, MXKRoomMemberDetailsViewControllerDelegate> {
|
||||
BOOL isAPNSRegistered;
|
||||
}
|
||||
|
||||
@property (strong, nonatomic) UIWindow *window;
|
||||
@property (strong, nonatomic) MasterTabBarController *masterTabBarController;
|
||||
|
||||
@property (strong, nonatomic) MXKAlert *errorNotification;
|
||||
|
||||
@property (strong, nonatomic) NSString *appVersion;
|
||||
@property (strong, nonatomic) NSString *build;
|
||||
|
||||
@property (nonatomic) BOOL isAppForeground;
|
||||
@property (nonatomic) BOOL isOffline;
|
||||
|
||||
+ (AppDelegate*)theDelegate;
|
||||
|
||||
- (void)selectMatrixAccount:(void (^)(MXKAccount *selectedAccount))onSelection;
|
||||
|
||||
- (void)registerUserNotificationSettings;
|
||||
|
||||
- (void)reloadMatrixSessions:(BOOL)clearCache;
|
||||
|
||||
- (void)logout;
|
||||
|
||||
- (MXKAlert*)showErrorAsAlert:(NSError*)error;
|
||||
|
||||
/**
|
||||
Reopen an existing private OneToOne room with this userId or creates a new one (if it doesn't exist)
|
||||
|
||||
@param userId
|
||||
*/
|
||||
- (void)startPrivateOneToOneRoomWithUserId:(NSString*)userId;
|
||||
|
||||
@end
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Vendored
BIN
Binary file not shown.
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
Copyright 2015 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.
|
||||
*/
|
||||
|
||||
/** Single, end-to-end encrypted messages (ie. we don't know what they say) */
|
||||
|
||||
/* New message from a specific person, not referencing a room */
|
||||
"MSG_FROM_USER" = "Message from %@";
|
||||
|
||||
/* New message from a specific person in a named room */
|
||||
"MSG_FROM_USER_IN_ROOM" = "%@ posted in %@";
|
||||
|
||||
/** Single, unencrypted messages (where we can include the content */
|
||||
|
||||
/* New message from a specific person, not referencing a room. Content included. */
|
||||
"MSG_FROM_USER_WITH_CONTENT" = "%@: %@";
|
||||
|
||||
/* New message from a specific person in a named room. Content included. */
|
||||
"MSG_FROM_USER_IN_ROOM_WITH_CONTENT" = "%@ in %@: %@";
|
||||
|
||||
/* New action message from a specific person, not referencing a room. */
|
||||
"ACTION_FROM_USER" = "* %@ %@";
|
||||
|
||||
/* New action message from a specific person in a named room. */
|
||||
"ACTION_FROM_USER_IN_ROOM" = "%@: * %@ %@";
|
||||
|
||||
/** Image Messages **/
|
||||
|
||||
/* New action message from a specific person, not referencing a room. */
|
||||
"IMAGE_FROM_USER" = "%@ sent you a picture";
|
||||
|
||||
/* New action message from a specific person in a named room. */
|
||||
"IMAGE_FROM_USER_IN_ROOM" = "%@ posted a picture in %@";
|
||||
|
||||
/** Coalesced messages **/
|
||||
|
||||
/* Multiple unread messages in a room */
|
||||
"UNREAD_IN_ROOM" = "%@ new messages in %@";
|
||||
|
||||
/* Multiple unread messages from a specific person, not referencing a room */
|
||||
"MSGS_FROM_USER" = "%@ new messages in %@";
|
||||
|
||||
/* Multiple unread messages from two people */
|
||||
"MSGS_FROM_TWO_USERS" = "%@ new messages from %@ and %@";
|
||||
|
||||
/* Multiple unread messages from three people */
|
||||
"MSGS_FROM_THREE_USERS" = "%@ new messages from %@, %@ and %@";
|
||||
|
||||
/* Multiple unread messages from two plus people (ie. for 4+ people: 'others' replaces the third person) */
|
||||
"MSGS_FROM_TWO_PLUS_USERS" = "%@ new messages from %@, %@ and others";
|
||||
|
||||
/* Multiple messages in two rooms */
|
||||
"MSGS_IN_TWO_ROOMS" = "%@ new messages in %@ and %@";
|
||||
|
||||
/* Look, stuff's happened, alright? Just open the app. */
|
||||
"MSGS_IN_TWO_PLUS_ROOMS" = "%@ new messages in %@, %@ and others";
|
||||
|
||||
/** Invites **/
|
||||
|
||||
/* A user has invited you to a chat */
|
||||
"USER_INVITE_TO_CHAT" = "%@ has invited you to chat";
|
||||
|
||||
/* A user has invited you to an (unamed) group chat */
|
||||
"USER_INVITE_TO_CHAT_GROUP_CHAT" = "%@ has invited you to a group chat";
|
||||
|
||||
/* A user has invited you to a named room */
|
||||
"USER_INVITE_TO_NAMED_ROOM" = "%@ has invited you to %@";
|
||||
|
||||
/** Calls **/
|
||||
|
||||
/* Incoming one-to-one voice call */
|
||||
"VOICE_CALL_FROM_USER" = "Call from %@";
|
||||
|
||||
/* Incoming one-to-one video call */
|
||||
"VIDEO_CALL_FROM_USER" = "Video call from %@";
|
||||
|
||||
/* Incoming unnamed voice conference invite from a specific person */
|
||||
"VOICE_CONF_FROM_USER" = "Group call from %@";
|
||||
|
||||
/* Incoming unnamed video conference invite from a specific person */
|
||||
"VIDEO_CONF_FROM_USER" = "Video group call from %@";
|
||||
|
||||
/* Incoming named voice conference invite from a specific person */
|
||||
"VOICE_CONF_NAMED_FROM_USER" = "Group call from %@: '%@'";
|
||||
|
||||
/* Incoming named video conference invite from a specific person */
|
||||
"VIDEO_CONF_NAMED_FROM_USER" = "Video group call from %@: '%@'";
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
Copyright 2015 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.
|
||||
*/
|
||||
|
||||
// Titles
|
||||
"recents" = "Recents";
|
||||
"accounts" = "Accounts";
|
||||
|
||||
// Others
|
||||
"bug_report_prompt" = "The application has crashed last time. Would you like to submit a crash report?";
|
||||
"rage_shake_prompt" = "You seem to be shaking the phone in frustration. Would you like to submit a bug report?";
|
||||
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="6214" systemVersion="14A314h" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6207"/>
|
||||
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
|
||||
</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>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text=" Copyright (c) 2015 matrix.org. All rights reserved." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="8ie-xW-0ye">
|
||||
<rect key="frame" x="20" y="439" width="441" height="21"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Vector" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="kId-c2-rCX">
|
||||
<rect key="frame" x="20" y="140" width="441" height="43"/>
|
||||
<fontDescription key="fontDescription" type="boldSystem" pointSize="36"/>
|
||||
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstItem="kId-c2-rCX" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="bottom" multiplier="1/3" constant="1" id="5cJ-9S-tgC"/>
|
||||
<constraint firstAttribute="centerX" secondItem="kId-c2-rCX" secondAttribute="centerX" id="Koa-jz-hwk"/>
|
||||
<constraint firstAttribute="bottom" secondItem="8ie-xW-0ye" secondAttribute="bottom" constant="20" id="Kzo-t9-V3l"/>
|
||||
<constraint firstItem="8ie-xW-0ye" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="MfP-vx-nX0"/>
|
||||
<constraint firstAttribute="centerX" secondItem="8ie-xW-0ye" secondAttribute="centerX" id="ZEH-qu-HZ9"/>
|
||||
<constraint firstItem="kId-c2-rCX" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="fvb-Df-36g"/>
|
||||
</constraints>
|
||||
<nil key="simulatedStatusBarMetrics"/>
|
||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
<point key="canvasLocation" x="548" y="455"/>
|
||||
</view>
|
||||
</objects>
|
||||
</document>
|
||||
@@ -0,0 +1,346 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="6751" systemVersion="14D131" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="GsA-m1-kGB">
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6736"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--RecentsNav-->
|
||||
<scene sceneID="pY4-Hu-kfo">
|
||||
<objects>
|
||||
<navigationController title="Recents" id="RMx-3f-FxP" userLabel="RecentsNav" sceneMemberID="viewController">
|
||||
<navigationBar key="navigationBar" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" id="Pmd-2v-anx">
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</navigationBar>
|
||||
<connections>
|
||||
<segue destination="Foe-o5-6Ud" kind="relationship" relationship="rootViewController" id="TOG-zb-B44"/>
|
||||
</connections>
|
||||
</navigationController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="8fS-aE-onr" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="918" y="-678"/>
|
||||
</scene>
|
||||
<!--Room-->
|
||||
<scene sceneID="UrN-g2-oG1">
|
||||
<objects>
|
||||
<viewController title="Room" id="msb-ol-2LB" customClass="RoomViewController" sceneMemberID="viewController">
|
||||
<navigationItem key="navigationItem" id="3Zt-Wl-J6o">
|
||||
<nil key="title"/>
|
||||
<view key="titleView" contentMode="scaleToFill" id="aas-th-FW1" userLabel="Room title view container">
|
||||
<rect key="frame" x="16" y="2" width="60" height="40"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
</view>
|
||||
<barButtonItem key="rightBarButtonItem" image="icon_users.png" id="3d6-ln-ICU" userLabel="showRoomMembers">
|
||||
<inset key="imageInsets" minX="0.0" minY="0.0" maxX="5" maxY="0.0"/>
|
||||
<connections>
|
||||
<action selector="showRoomMembers:" destination="msb-ol-2LB" id="Ouh-KX-Nj7"/>
|
||||
<segue destination="y7N-Cs-bXh" kind="show" identifier="showMemberList" id="CyV-7r-Ykf"/>
|
||||
</connections>
|
||||
</barButtonItem>
|
||||
</navigationItem>
|
||||
<connections>
|
||||
<outlet property="roomTitleViewContainer" destination="aas-th-FW1" id="SFz-1s-ywg"/>
|
||||
<outlet property="showRoomMembersButtonItem" destination="3d6-ln-ICU" id="Qh7-yj-G7e"/>
|
||||
<segue destination="qlN-Mb-ZH7" kind="show" identifier="showMemberDetails" id="9Sj-Yf-p2I"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="94y-cU-qQD" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="1596" y="81"/>
|
||||
</scene>
|
||||
<!--Contact Details View Controller-->
|
||||
<scene sceneID="aUh-hv-QyM">
|
||||
<objects>
|
||||
<tableViewController id="ro1-6w-v07" customClass="MXKContactDetailsViewController" sceneMemberID="viewController"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="cKT-B6-clR" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="1517" y="801"/>
|
||||
</scene>
|
||||
<!--Room Members-->
|
||||
<scene sceneID="5AK-8u-TUO">
|
||||
<objects>
|
||||
<tableViewController id="y7N-Cs-bXh" userLabel="Room Members" customClass="RoomMembersViewController" sceneMemberID="viewController">
|
||||
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" id="Oe9-1Y-zhS">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<connections>
|
||||
<outlet property="dataSource" destination="y7N-Cs-bXh" id="9Zb-6m-GNy"/>
|
||||
<outlet property="delegate" destination="y7N-Cs-bXh" id="RVg-Nq-nNy"/>
|
||||
</connections>
|
||||
</tableView>
|
||||
<connections>
|
||||
<segue destination="qlN-Mb-ZH7" kind="show" identifier="showDetails" id="m9P-N3-WZN"/>
|
||||
</connections>
|
||||
</tableViewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="Exe-4N-jYR" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="2895" y="-290"/>
|
||||
</scene>
|
||||
<!--Room Member Details View Controller-->
|
||||
<scene sceneID="q1J-Wz-aLa">
|
||||
<objects>
|
||||
<tableViewController id="qlN-Mb-ZH7" customClass="MXKRoomMemberDetailsViewController" sceneMemberID="viewController"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="mrY-z4-HGF" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="2895" y="488"/>
|
||||
</scene>
|
||||
<!--Home-->
|
||||
<scene sceneID="ZM8-lp-XE5">
|
||||
<objects>
|
||||
<viewController id="U6w-lp-S4A" customClass="HomeViewController" sceneMemberID="viewController">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="vDd-9N-DDP"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="dPJ-aO-2kU"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="RoP-22-pJ3">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<searchBar contentMode="redraw" showsCancelButton="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Tvw-ed-GsF">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="44"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="44" id="eLI-EI-r3h"/>
|
||||
</constraints>
|
||||
<textInputTraits key="textInputTraits" returnKeyType="done"/>
|
||||
<connections>
|
||||
<outlet property="delegate" destination="U6w-lp-S4A" id="hCd-1N-xoi"/>
|
||||
</connections>
|
||||
</searchBar>
|
||||
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" keyboardDismissMode="interactive" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" translatesAutoresizingMaskIntoConstraints="NO" id="JaR-EZ-kVC">
|
||||
<rect key="frame" x="0.0" y="44" width="600" height="556"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<connections>
|
||||
<outlet property="dataSource" destination="U6w-lp-S4A" id="4wm-Hk-riw"/>
|
||||
<outlet property="delegate" destination="U6w-lp-S4A" id="1Td-A7-K3v"/>
|
||||
</connections>
|
||||
</tableView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="bottom" secondItem="JaR-EZ-kVC" secondAttribute="bottom" id="4Gb-U6-it8"/>
|
||||
<constraint firstItem="Tvw-ed-GsF" firstAttribute="leading" secondItem="RoP-22-pJ3" secondAttribute="leading" id="729-XV-ZMk"/>
|
||||
<constraint firstAttribute="trailing" secondItem="Tvw-ed-GsF" secondAttribute="trailing" id="Bus-cz-B6K"/>
|
||||
<constraint firstItem="JaR-EZ-kVC" firstAttribute="leading" secondItem="RoP-22-pJ3" secondAttribute="leading" id="I6V-D3-pAd"/>
|
||||
<constraint firstItem="Tvw-ed-GsF" firstAttribute="top" secondItem="RoP-22-pJ3" secondAttribute="top" id="Mow-Cu-hMJ"/>
|
||||
<constraint firstAttribute="trailing" secondItem="JaR-EZ-kVC" secondAttribute="trailing" id="oEj-zz-ioV"/>
|
||||
<constraint firstItem="JaR-EZ-kVC" firstAttribute="top" secondItem="Tvw-ed-GsF" secondAttribute="bottom" id="pmM-LQ-f57"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<navigationItem key="navigationItem" title="Home" id="soS-1K-ngS"/>
|
||||
<connections>
|
||||
<outlet property="publicRoomsSearchBar" destination="Tvw-ed-GsF" id="xfg-cb-f7H"/>
|
||||
<outlet property="publicRoomsSearchBarHeightConstraint" destination="eLI-EI-r3h" id="NLK-zk-hqf"/>
|
||||
<outlet property="publicRoomsSearchBarTopConstraint" destination="Mow-Cu-hMJ" id="FKY-yE-XsQ"/>
|
||||
<outlet property="tableView" destination="JaR-EZ-kVC" id="iOr-IF-WMm"/>
|
||||
<outlet property="tableViewBottomConstraint" destination="4Gb-U6-it8" id="WZq-Ll-iM9"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="jbe-3b-94N" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="911" y="-1492"/>
|
||||
</scene>
|
||||
<!--Authentication View Controller-->
|
||||
<scene sceneID="FoA-N2-3aF">
|
||||
<objects>
|
||||
<viewController id="ZlD-EU-ncw" customClass="AuthenticationViewController" sceneMemberID="viewController">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="crg-iM-twR"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="gbK-Nm-HUT"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="wIi-Yi-2pi">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</view>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="mvZ-se-pqQ" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="55" y="-2252"/>
|
||||
</scene>
|
||||
<!--HomeNav-->
|
||||
<scene sceneID="whS-JX-66Y">
|
||||
<objects>
|
||||
<navigationController title="HomeNav" id="11T-cf-rgo" sceneMemberID="viewController">
|
||||
<tabBarItem key="tabBarItem" title="Home" image="tab_home.ico" id="aQW-fV-f8t"/>
|
||||
<navigationBar key="navigationBar" contentMode="scaleToFill" id="HZK-D9-mlB">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</navigationBar>
|
||||
<connections>
|
||||
<segue destination="U6w-lp-S4A" kind="relationship" relationship="rootViewController" id="vCz-RO-a89"/>
|
||||
</connections>
|
||||
</navigationController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="Fpd-U8-xAp" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="49" y="-1492"/>
|
||||
</scene>
|
||||
<!--TabBar-->
|
||||
<scene sceneID="ONA-qQ-ve3">
|
||||
<objects>
|
||||
<tabBarController title="TabBar" id="GsA-m1-kGB" customClass="MasterTabBarController" sceneMemberID="viewController">
|
||||
<nil key="simulatedBottomBarMetrics"/>
|
||||
<tabBar key="tabBar" contentMode="scaleToFill" id="n7O-7P-Gti">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="49"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
</tabBar>
|
||||
<connections>
|
||||
<segue destination="ZlD-EU-ncw" kind="presentation" identifier="showAuth" id="Yfo-em-Rs3"/>
|
||||
<segue destination="11T-cf-rgo" kind="relationship" relationship="viewControllers" id="eov-7h-qzl"/>
|
||||
<segue destination="H1p-Uh-vWS" kind="relationship" relationship="viewControllers" id="Iju-mu-cRD"/>
|
||||
<segue destination="fsw-DP-sy3" kind="relationship" relationship="viewControllers" id="8ex-NL-bWb"/>
|
||||
<segue destination="g3a-7T-Pjt" kind="relationship" relationship="viewControllers" id="Y6R-1Q-Uhv"/>
|
||||
</connections>
|
||||
</tabBarController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="EVG-PE-ktX" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="-1041" y="-273"/>
|
||||
</scene>
|
||||
<!--Contacts-->
|
||||
<scene sceneID="ViO-cb-0j7">
|
||||
<objects>
|
||||
<tableViewController id="v0E-AX-Hfa" userLabel="Contacts" customClass="ContactsViewController" sceneMemberID="viewController">
|
||||
<navigationItem key="navigationItem" title="Contacts" id="Ppm-q1-NgB"/>
|
||||
<connections>
|
||||
<segue destination="ro1-6w-v07" kind="show" identifier="showContactDetails" id="8v9-F6-vUy"/>
|
||||
</connections>
|
||||
</tableViewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="YV3-Df-XS8" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="795" y="801"/>
|
||||
</scene>
|
||||
<!--Settings-->
|
||||
<scene sceneID="4CK-43-kSo">
|
||||
<objects>
|
||||
<tableViewController id="1TJ-Md-cjN" customClass="SettingsViewController" sceneMemberID="viewController">
|
||||
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" keyboardDismissMode="interactive" dataMode="prototypes" style="grouped" separatorStyle="default" rowHeight="44" sectionHeaderHeight="10" sectionFooterHeight="10" id="etG-ZU-b2r">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" red="0.93725490196078431" green="0.93725490196078431" blue="0.95686274509803926" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<connections>
|
||||
<outlet property="dataSource" destination="1TJ-Md-cjN" id="Lqt-w3-NjQ"/>
|
||||
<outlet property="delegate" destination="1TJ-Md-cjN" id="pgx-SX-xgc"/>
|
||||
</connections>
|
||||
</tableView>
|
||||
<navigationItem key="navigationItem" title="Settings" id="7NM-zW-wJT"/>
|
||||
<connections>
|
||||
<segue destination="KeQ-Sp-kmH" kind="show" identifier="showAccountDetails" id="flf-61-vgV"/>
|
||||
<segue destination="ZlD-EU-ncw" kind="show" identifier="addAccount" id="17E-G9-IZ6"/>
|
||||
</connections>
|
||||
</tableViewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="ZKJ-22-Asy" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="880" y="2020"/>
|
||||
</scene>
|
||||
<!--Account Details View Controller-->
|
||||
<scene sceneID="V8G-Oz-3KA">
|
||||
<objects>
|
||||
<tableViewController id="KeQ-Sp-kmH" customClass="AccountDetailsViewController" sceneMemberID="viewController">
|
||||
<connections>
|
||||
<segue destination="h5x-Kb-9pa" kind="show" identifier="showGlobalNotificationSettings" id="kgj-1g-opx"/>
|
||||
</connections>
|
||||
</tableViewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="KBx-ZK-1zU" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="1661" y="2022"/>
|
||||
</scene>
|
||||
<!--Global notification settings-->
|
||||
<scene sceneID="QZt-ZR-Vkj">
|
||||
<objects>
|
||||
<tableViewController title="Global notification settings" id="h5x-Kb-9pa" customClass="GlobalNotificationSettingsViewController" sceneMemberID="viewController"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="iOf-Cf-2Ew" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="1661" y="2776"/>
|
||||
</scene>
|
||||
<!--SettingsNav-->
|
||||
<scene sceneID="b0q-mf-7ii">
|
||||
<objects>
|
||||
<navigationController title="SettingsNav" id="g3a-7T-Pjt" sceneMemberID="viewController">
|
||||
<tabBarItem key="tabBarItem" title="Settings" image="tab_settings.png" id="3O7-Cp-aRc"/>
|
||||
<navigationBar key="navigationBar" contentMode="scaleToFill" id="bra-h0-es4">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</navigationBar>
|
||||
<connections>
|
||||
<segue destination="1TJ-Md-cjN" kind="relationship" relationship="rootViewController" id="VCU-F9-Tew"/>
|
||||
</connections>
|
||||
</navigationController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="itc-5f-CfR" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="60" y="2022"/>
|
||||
</scene>
|
||||
<!--RecentsSplitVC-->
|
||||
<scene sceneID="Nki-YV-4Qg">
|
||||
<objects>
|
||||
<splitViewController title="RecentsSplitVC" id="H1p-Uh-vWS" sceneMemberID="viewController">
|
||||
<tabBarItem key="tabBarItem" systemItem="recents" id="mXn-Bx-qzv"/>
|
||||
<toolbarItems/>
|
||||
<connections>
|
||||
<segue destination="RMx-3f-FxP" kind="relationship" relationship="masterViewController" id="BlO-5A-QYV"/>
|
||||
<segue destination="vC3-pB-5Vb" kind="relationship" relationship="detailViewController" id="0ws-cL-0tk"/>
|
||||
</connections>
|
||||
</splitViewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="cZU-Oi-B1e" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="60" y="-266"/>
|
||||
</scene>
|
||||
<!--Recents View Controller-->
|
||||
<scene sceneID="EAJ-Vu-76j">
|
||||
<objects>
|
||||
<viewController id="Foe-o5-6Ud" customClass="RecentsViewController" sceneMemberID="viewController">
|
||||
<navigationItem key="navigationItem" id="6sO-OP-7Sv"/>
|
||||
<connections>
|
||||
<segue destination="vC3-pB-5Vb" kind="showDetail" identifier="showDetails" id="Vo4-8x-dtH"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="Po3-cj-dhS" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="1596" y="-678"/>
|
||||
</scene>
|
||||
<!--RoomNav-->
|
||||
<scene sceneID="r7l-gg-dq7">
|
||||
<objects>
|
||||
<navigationController title="RoomNav" id="vC3-pB-5Vb" sceneMemberID="viewController">
|
||||
<navigationBar key="navigationBar" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" id="DjV-YW-jjY">
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</navigationBar>
|
||||
<connections>
|
||||
<segue destination="msb-ol-2LB" kind="relationship" relationship="rootViewController" id="5tu-jh-ZP6"/>
|
||||
</connections>
|
||||
</navigationController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="SLD-UC-DBI" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="911" y="81"/>
|
||||
</scene>
|
||||
<!--ContactsNav-->
|
||||
<scene sceneID="HhC-eK-eSS">
|
||||
<objects>
|
||||
<navigationController title="ContactsNav" id="fsw-DP-sy3" sceneMemberID="viewController">
|
||||
<tabBarItem key="tabBarItem" systemItem="contacts" id="nIx-2f-mmH"/>
|
||||
<simulatedTabBarMetrics key="simulatedBottomBarMetrics"/>
|
||||
<navigationBar key="navigationBar" contentMode="scaleToFill" id="gsI-4i-BX6">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</navigationBar>
|
||||
<connections>
|
||||
<segue destination="v0E-AX-Hfa" kind="relationship" relationship="rootViewController" id="Jwg-1B-PqQ"/>
|
||||
</connections>
|
||||
</navigationController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="C6c-tb-ElJ" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="55" y="802"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
<resources>
|
||||
<image name="icon_users.png" width="35" height="25"/>
|
||||
<image name="tab_home.ico" width="16" height="16"/>
|
||||
<image name="tab_settings.png" width="25" height="25"/>
|
||||
</resources>
|
||||
<inferredMetricsTieBreakers>
|
||||
<segue reference="Vo4-8x-dtH"/>
|
||||
<segue reference="9Sj-Yf-p2I"/>
|
||||
<segue reference="17E-G9-IZ6"/>
|
||||
</inferredMetricsTieBreakers>
|
||||
</document>
|
||||
@@ -0,0 +1,68 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "29x29",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "29x29",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "40x40",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "40x40",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "60x60",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "60x60",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "29x29",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "29x29",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "40x40",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "40x40",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "76x76",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "76x76",
|
||||
"scale" : "2x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
<?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>UIStatusBarHidden</key>
|
||||
<false/>
|
||||
<key>UserDefaults</key>
|
||||
<string>${PRODUCT_NAME}-Defaults</string>
|
||||
<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>CFBundleDisplayName</key>
|
||||
<string>Vector</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.0.1</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>0</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>UIBackgroundModes</key>
|
||||
<array>
|
||||
<string>remote-notification</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>
|
||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||
<false/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
Copyright 2015 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 <MatrixKit/MatrixKit.h>
|
||||
|
||||
/**
|
||||
The data source for Console `RecentsViewController`.
|
||||
*/
|
||||
@interface RecentListDataSource : MXKInterleavedRecentsDataSource
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
Copyright 2015 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 "RecentListDataSource.h"
|
||||
|
||||
#import "AppDelegate.h"
|
||||
|
||||
@implementation RecentListDataSource
|
||||
|
||||
#pragma mark - UITableViewDataSource
|
||||
|
||||
- (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
|
||||
id<MXKRecentCellDataStoring> recentCellData = [self cellDataAtIndexPath:indexPath];
|
||||
|
||||
// cancel pending uploads/downloads
|
||||
// they are useless by now
|
||||
[MXKMediaManager cancelDownloadsInCacheFolder:recentCellData.roomDataSource.room.state.roomId];
|
||||
// TODO GFO cancel pending uploads related to this room
|
||||
|
||||
[recentCellData.roomDataSource.room leave:^{
|
||||
// Refresh table display
|
||||
if (self.delegate) {
|
||||
[self.delegate dataSource:self didCellChange:nil];
|
||||
}
|
||||
} failure:^(NSError *error) {
|
||||
NSLog(@"[Console RecentListDataSource] Failed to leave room (%@) failed: %@", recentCellData.roomDataSource.room.state.roomId, error);
|
||||
//Alert user
|
||||
[[AppDelegate theDelegate] showErrorAsAlert:error];
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,34 @@
|
||||
<?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>identityserverurl</key>
|
||||
<string>https://matrix.org</string>
|
||||
<key>homeserverurl</key>
|
||||
<string>https://matrix.org</string>
|
||||
<key>homeserver</key>
|
||||
<string>matrix.org</string>
|
||||
<key>apnsDeviceToken</key>
|
||||
<string></string>
|
||||
<key>showAllEventsInRoomHistory</key>
|
||||
<false/>
|
||||
<key>showRedactionsInRoomHistory</key>
|
||||
<false/>
|
||||
<key>showUnsupportedEventsInRoomHistory</key>
|
||||
<false/>
|
||||
<key>sortRoomMembersUsingLastSeenTime</key>
|
||||
<true/>
|
||||
<key>showLeftMembersInRoomMemberList</key>
|
||||
<false/>
|
||||
<key>syncLocalContacts</key>
|
||||
<false/>
|
||||
<key>maxAllowedMediaCacheSize</key>
|
||||
<integer>1073741824</integer>
|
||||
<key>presenceColorForOnlineUser</key>
|
||||
<integer>3401011</integer>
|
||||
<key>presenceColorForUnavailableUser</key>
|
||||
<integer>15066368</integer>
|
||||
<key>presenceColorForOfflineUser</key>
|
||||
<integer>15020851</integer>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
Copyright 2015 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 <MatrixKit/MatrixKit.h>
|
||||
|
||||
@interface AccountDetailsViewController : MXKAccountDetailsViewController
|
||||
|
||||
@end
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
Copyright 2015 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 "AccountDetailsViewController.h"
|
||||
|
||||
#import "RageShakeManager.h"
|
||||
|
||||
@interface AccountDetailsViewController()
|
||||
{
|
||||
NSInteger globalNotificationSettingsRowIndex;
|
||||
|
||||
// The "Global Notification Settings" button
|
||||
UIButton *globalNotifSettingsButton;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation AccountDetailsViewController
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
// Do any additional setup after loading the view, typically from a nib.
|
||||
|
||||
// Setup `MXKRoomMemberListViewController` properties
|
||||
self.rageShakeManager = [RageShakeManager sharedManager];
|
||||
}
|
||||
|
||||
- (void)destroy
|
||||
{
|
||||
[super destroy];
|
||||
|
||||
globalNotifSettingsButton = nil;
|
||||
}
|
||||
|
||||
#pragma mark - TableView data source
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
|
||||
{
|
||||
NSInteger count = [super tableView:tableView numberOfRowsInSection:section];
|
||||
|
||||
// Add one button in notification section to edit global notification settings
|
||||
if (section == notificationsSection)
|
||||
{
|
||||
globalNotificationSettingsRowIndex = count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
UITableViewCell *cell;
|
||||
|
||||
if (indexPath.section == notificationsSection && indexPath.row == globalNotificationSettingsRowIndex)
|
||||
{
|
||||
MXKTableViewCellWithButton *globalNotifSettingsBtnCell = [tableView dequeueReusableCellWithIdentifier:[MXKTableViewCellWithButton defaultReuseIdentifier]];
|
||||
if (!globalNotifSettingsBtnCell)
|
||||
{
|
||||
globalNotifSettingsBtnCell = [[MXKTableViewCellWithButton alloc] init];
|
||||
}
|
||||
[globalNotifSettingsBtnCell.mxkButton setTitle:NSLocalizedStringFromTable(@"notification_settings_global_notification_settings", @"MatrixConsole", nil) forState:UIControlStateNormal];
|
||||
[globalNotifSettingsBtnCell.mxkButton setTitle:NSLocalizedStringFromTable(@"notification_settings_global_notification_settings", @"MatrixConsole", nil) forState:UIControlStateHighlighted];
|
||||
[globalNotifSettingsBtnCell.mxkButton addTarget:self action:@selector(onButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
|
||||
|
||||
globalNotifSettingsButton = globalNotifSettingsBtnCell.mxkButton;
|
||||
|
||||
cell = globalNotifSettingsBtnCell;
|
||||
|
||||
|
||||
// MXKTableViewCellWithTextView *userInfoCell = [tableView dequeueReusableCellWithIdentifier:[MXKTableViewCellWithTextView defaultReuseIdentifier]];
|
||||
// if (!userInfoCell)
|
||||
// {
|
||||
// userInfoCell = [[MXKTableViewCellWithTextView alloc] init];
|
||||
// }
|
||||
//
|
||||
// userInfoCell.mxkTextView.text = NSLocalizedStringFromTable(@"settings_webclient_push", @"MatrixConsole", nil);
|
||||
// cell = userInfoCell;
|
||||
}
|
||||
else
|
||||
{
|
||||
cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];
|
||||
}
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - TableView delegate
|
||||
|
||||
//- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
//{
|
||||
// if (indexPath.section == notificationsSection)
|
||||
// {
|
||||
// if (indexPath.row == globalNotificationSettingsRowIndex)
|
||||
// {
|
||||
// UITextView *textView = [[UITextView alloc] initWithFrame:CGRectMake(0, 0, tableView.frame.size.width, MAXFLOAT)];
|
||||
// textView.font = [UIFont systemFontOfSize:14];
|
||||
// textView.text = NSLocalizedStringFromTable(@"settings_webclient_push", @"MatrixConsole", nil);
|
||||
// CGSize contentSize = [textView sizeThatFits:textView.frame.size];
|
||||
// return contentSize.height + 1;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return [super tableView:tableView heightForRowAtIndexPath:indexPath];
|
||||
//}
|
||||
|
||||
- (void)onButtonPressed:(id)sender
|
||||
{
|
||||
if (sender == globalNotifSettingsButton)
|
||||
{
|
||||
[self performSegueWithIdentifier:@"showGlobalNotificationSettings" sender:self];
|
||||
}
|
||||
else
|
||||
{
|
||||
[super onButtonPressed:sender];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Segues
|
||||
|
||||
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
|
||||
{
|
||||
// Keep ref on destinationViewController
|
||||
[super prepareForSegue:segue sender:sender];
|
||||
|
||||
if ([[segue identifier] isEqualToString:@"showGlobalNotificationSettings"])
|
||||
{
|
||||
MXKNotificationSettingsViewController *notifSettingsViewController = segue.destinationViewController;
|
||||
notifSettingsViewController.mxAccount = self.mxAccount;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
Copyright 2015 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 <MatrixKit/MatrixKit.h>
|
||||
|
||||
@interface AuthenticationViewController : MXKAuthenticationViewController <MXKAuthenticationViewControllerDelegate>
|
||||
|
||||
@end
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
Copyright 2015 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 "AuthenticationViewController.h"
|
||||
|
||||
#import "RageShakeManager.h"
|
||||
|
||||
@implementation AuthenticationViewController
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
|
||||
// Setup `MXKAuthenticationViewController` properties
|
||||
self.rageShakeManager = [RageShakeManager sharedManager];
|
||||
self.defaultHomeServerUrl = [[NSUserDefaults standardUserDefaults] objectForKey:@"homeserverurl"];
|
||||
self.defaultIdentityServerUrl = [[NSUserDefaults standardUserDefaults] objectForKey:@"identityserverurl"];
|
||||
|
||||
// The view controller dismiss itself on successful login.
|
||||
self.delegate = self;
|
||||
}
|
||||
|
||||
#pragma mark - MXKAuthenticationViewControllerDelegate
|
||||
|
||||
- (void)authenticationViewController:(MXKAuthenticationViewController *)authenticationViewController didLogWithUserId:(NSString *)userId {
|
||||
|
||||
// Report server url typed by the user as default url.
|
||||
if (self.homeServerTextField.text.length) {
|
||||
[[NSUserDefaults standardUserDefaults] setObject:self.homeServerTextField.text forKey:@"homeserverurl"];
|
||||
}
|
||||
if (self.identityServerTextField.text.length) {
|
||||
[[NSUserDefaults standardUserDefaults] setObject:self.identityServerTextField.text forKey:@"identityserverurl"];
|
||||
}
|
||||
[[NSUserDefaults standardUserDefaults] synchronize];
|
||||
|
||||
// Remove auth view controller on successful login
|
||||
if (self.navigationController) {
|
||||
// Pop the view controller
|
||||
[self.navigationController popViewControllerAnimated:YES];
|
||||
} else {
|
||||
// Dismiss on successful login
|
||||
[self dismissViewControllerAnimated:YES completion:nil];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
Copyright 2015 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 <MatrixKit/MatrixKit.h>
|
||||
|
||||
// SMS
|
||||
#import <MessageUI/MessageUI.h>
|
||||
#import <MessageUI/MFMessageComposeViewController.h>
|
||||
|
||||
/**
|
||||
'ContactsViewController' inherits MXKContactListViewController to handle contact list.
|
||||
*/
|
||||
@interface ContactsViewController : MXKContactListViewController <MXKContactListViewControllerDelegate, MFMessageComposeViewControllerDelegate>
|
||||
@end
|
||||
|
||||
@@ -0,0 +1,285 @@
|
||||
/*
|
||||
Copyright 2015 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 "ContactsViewController.h"
|
||||
|
||||
#import "AppDelegate.h"
|
||||
|
||||
#import "RageShakeManager.h"
|
||||
|
||||
#import "NSBundle+MatrixKit.h"
|
||||
|
||||
@interface ContactsViewController ()
|
||||
{
|
||||
/**
|
||||
Tap on thumbnail --> display matrix information.
|
||||
*/
|
||||
MXKContact* selectedContact;
|
||||
}
|
||||
|
||||
@property (strong, nonatomic) MXKAlert *startChatMenu;
|
||||
@property (strong, nonatomic) MXKAlert *allowContactSyncAlert;
|
||||
@end
|
||||
|
||||
@implementation ContactsViewController
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
|
||||
[self.tableView setSectionIndexColor:[AppDelegate theDelegate].masterTabBarController.tabBar.tintColor];
|
||||
[self.tableView setSectionIndexBackgroundColor:[UIColor clearColor]];
|
||||
|
||||
// Set rageShake handler
|
||||
self.rageShakeManager = [RageShakeManager sharedManager];
|
||||
|
||||
// The view controller handles itself the selected contact
|
||||
self.delegate = self;
|
||||
}
|
||||
|
||||
- (void)destroy
|
||||
{
|
||||
if (self.startChatMenu)
|
||||
{
|
||||
[self.startChatMenu dismiss:NO];
|
||||
}
|
||||
if (self.allowContactSyncAlert)
|
||||
{
|
||||
[self.allowContactSyncAlert dismiss:NO];
|
||||
}
|
||||
|
||||
selectedContact = nil;
|
||||
|
||||
[super destroy];
|
||||
}
|
||||
|
||||
#pragma mark - Actions
|
||||
|
||||
- (IBAction)onSegmentValueChange:(id)sender
|
||||
{
|
||||
[super onSegmentValueChange:sender];
|
||||
|
||||
if (sender == self.contactsControls)
|
||||
{
|
||||
// Did the user select local contacts?
|
||||
if (self.contactsControls.selectedSegmentIndex)
|
||||
{
|
||||
MXKAppSettings* appSettings = [MXKAppSettings standardAppSettings];
|
||||
|
||||
if (!appSettings.syncLocalContacts)
|
||||
{
|
||||
__weak typeof(self) weakSelf = self;
|
||||
|
||||
self.allowContactSyncAlert = [[MXKAlert alloc] initWithTitle:NSLocalizedStringFromTable(@"contact_local_sync_prompt", @"MatrixConsole", nil) message:nil style:MXKAlertStyleAlert];
|
||||
|
||||
[self.allowContactSyncAlert addActionWithTitle:[NSBundle mxk_localizedStringForKey:@"no"] style:MXKAlertActionStyleDefault handler:^(MXKAlert *alert)
|
||||
{
|
||||
weakSelf.allowContactSyncAlert = nil;
|
||||
}];
|
||||
|
||||
[self.allowContactSyncAlert addActionWithTitle:[NSBundle mxk_localizedStringForKey:@"yes"] style:MXKAlertActionStyleDefault handler:^(MXKAlert *alert)
|
||||
{
|
||||
weakSelf.allowContactSyncAlert = nil;
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
appSettings.syncLocalContacts = YES;
|
||||
[weakSelf.tableView reloadData];
|
||||
});
|
||||
}];
|
||||
|
||||
[self.allowContactSyncAlert showInViewController:self];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - MXKContactListViewControllerDelegate
|
||||
|
||||
- (void)contactListViewController:(MXKContactListViewController *)contactListViewController didSelectContact:(NSString*)contactId
|
||||
{
|
||||
MXKContact *contact = [[MXKContactManager sharedManager] contactWithContactID:contactId];
|
||||
|
||||
__weak typeof(self) weakSelf = self;
|
||||
NSArray* matrixIDs = contact.matrixIdentifiers;
|
||||
|
||||
// matrix user ?
|
||||
if (matrixIDs.count)
|
||||
{
|
||||
// Display action sheet only if at least one session is available for this user
|
||||
BOOL isSessionAvailable = NO;
|
||||
|
||||
NSArray *mxSessions = self.mxSessions;
|
||||
for (NSString* userID in matrixIDs)
|
||||
{
|
||||
for (MXSession *mxSession in mxSessions)
|
||||
{
|
||||
if ([mxSession userWithUserId:userID])
|
||||
{
|
||||
isSessionAvailable = YES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isSessionAvailable)
|
||||
{
|
||||
// only 1 matrix ID
|
||||
if (matrixIDs.count == 1)
|
||||
{
|
||||
NSString* matrixID = [matrixIDs objectAtIndex:0];
|
||||
|
||||
self.startChatMenu = [[MXKAlert alloc] initWithTitle:[NSString stringWithFormat:NSLocalizedStringFromTable(@"chat_with_user", @"MatrixConsole", nil), matrixID] message:nil style:MXKAlertStyleAlert];
|
||||
|
||||
[self.startChatMenu addActionWithTitle:[NSBundle mxk_localizedStringForKey:@"cancel"] style:MXKAlertActionStyleDefault handler:^(MXKAlert *alert)
|
||||
{
|
||||
weakSelf.startChatMenu = nil;
|
||||
}];
|
||||
|
||||
[self.startChatMenu addActionWithTitle:[NSBundle mxk_localizedStringForKey:@"ok"] style:MXKAlertActionStyleDefault handler:^(MXKAlert *alert)
|
||||
{
|
||||
weakSelf.startChatMenu = nil;
|
||||
|
||||
[[AppDelegate theDelegate] startPrivateOneToOneRoomWithUserId:matrixID];
|
||||
}];
|
||||
}
|
||||
else
|
||||
{
|
||||
self.startChatMenu = [[MXKAlert alloc] initWithTitle:NSLocalizedStringFromTable(@"chat_with", @"MatrixConsole", nil) message:nil style:MXKAlertStyleActionSheet];
|
||||
|
||||
for(NSString* matrixID in matrixIDs)
|
||||
{
|
||||
[self.startChatMenu addActionWithTitle:matrixID style:MXKAlertActionStyleDefault handler:^(MXKAlert *alert)
|
||||
{
|
||||
weakSelf.startChatMenu = nil;
|
||||
|
||||
[[AppDelegate theDelegate] startPrivateOneToOneRoomWithUserId:matrixID];
|
||||
}];
|
||||
}
|
||||
|
||||
[self.startChatMenu addActionWithTitle:[NSBundle mxk_localizedStringForKey:@"cancel"] style:MXKAlertActionStyleDefault handler:^(MXKAlert *alert)
|
||||
{
|
||||
weakSelf.startChatMenu = nil;
|
||||
}];
|
||||
|
||||
self.startChatMenu.sourceView = self.tableView;
|
||||
}
|
||||
|
||||
[self.startChatMenu showInViewController:self];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// invite to use matrix
|
||||
if (([MFMessageComposeViewController canSendText] ? contact.emailAddresses.count : 0) + (contact.phoneNumbers.count > 0))
|
||||
{
|
||||
|
||||
self.startChatMenu = [[MXKAlert alloc] initWithTitle:[NSString stringWithFormat:NSLocalizedStringFromTable(@"invite_this_user_to_use_matrix", @"MatrixConsole", nil)] message:nil style:MXKAlertStyleActionSheet];
|
||||
|
||||
// check if the target can send SMSes
|
||||
if ([MFMessageComposeViewController canSendText])
|
||||
{
|
||||
// list phonenumbers
|
||||
for(MXKPhoneNumber* phonenumber in contact.phoneNumbers)
|
||||
{
|
||||
[self.startChatMenu addActionWithTitle:phonenumber.textNumber style:MXKAlertActionStyleDefault handler:^(MXKAlert *alert)
|
||||
{
|
||||
weakSelf.startChatMenu = nil;
|
||||
|
||||
// launch SMS composer
|
||||
MFMessageComposeViewController *messageComposer = [[MFMessageComposeViewController alloc] init];
|
||||
|
||||
if (messageComposer)
|
||||
|
||||
{
|
||||
messageComposer.messageComposeDelegate = weakSelf;
|
||||
messageComposer.body = NSLocalizedStringFromTable(@"invitation_message", @"MatrixConsole", nil);
|
||||
messageComposer.recipients = [NSArray arrayWithObject:phonenumber.textNumber];
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[weakSelf presentViewController:messageComposer animated:YES completion:nil];
|
||||
});
|
||||
}
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
// list emails
|
||||
for(MXKEmail* email in contact.emailAddresses)
|
||||
{
|
||||
[self.startChatMenu addActionWithTitle:email.emailAddress style:MXKAlertActionStyleDefault handler:^(MXKAlert *alert)
|
||||
{
|
||||
weakSelf.startChatMenu = nil;
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
|
||||
NSString* subject = [NSLocalizedStringFromTable(@"invitation_subject", @"MatrixConsole", nil) stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
|
||||
NSString* body = [NSLocalizedStringFromTable(@"invitation_message", @"MatrixConsole", nil) stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
|
||||
|
||||
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"mailto:%@?subject=%@&body=%@", email.emailAddress, subject, body]]];
|
||||
});
|
||||
}];
|
||||
}
|
||||
|
||||
[self.startChatMenu addActionWithTitle:[NSBundle mxk_localizedStringForKey:@"cancel"] style:MXKAlertActionStyleDefault handler:^(MXKAlert *alert)
|
||||
{
|
||||
weakSelf.startChatMenu = nil;
|
||||
}];
|
||||
|
||||
self.startChatMenu.sourceView = self.tableView;
|
||||
[self.startChatMenu showInViewController:self];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)contactListViewController:(MXKContactListViewController *)contactListViewController didTapContactThumbnail:(NSString*)contactId
|
||||
{
|
||||
MXKContact *contact = [[MXKContactManager sharedManager] contactWithContactID:contactId];
|
||||
|
||||
// open detailled sheet if there
|
||||
if (contact.matrixIdentifiers.count > 0)
|
||||
{
|
||||
selectedContact = contact;
|
||||
[self performSegueWithIdentifier:@"showContactDetails" sender:self];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Segues
|
||||
|
||||
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
|
||||
{
|
||||
// Keep ref on destinationViewController
|
||||
[super prepareForSegue:segue sender:sender];
|
||||
|
||||
if ([segue.identifier isEqualToString:@"showContactDetails"])
|
||||
{
|
||||
MXKContactDetailsViewController *contactDetailsViewController = segue.destinationViewController;
|
||||
// Set rageShake handler
|
||||
contactDetailsViewController.rageShakeManager = [RageShakeManager sharedManager];
|
||||
// Set delegate to handle start chat option
|
||||
contactDetailsViewController.delegate = [AppDelegate theDelegate];
|
||||
|
||||
contactDetailsViewController.contact = selectedContact;
|
||||
selectedContact = nil;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark MFMessageComposeViewControllerDelegate
|
||||
|
||||
- (void)messageComposeViewController:(MFMessageComposeViewController *)controller didFinishWithResult:(MessageComposeResult)result
|
||||
{
|
||||
[self dismissViewControllerAnimated:YES completion:nil];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
Copyright 2015 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 <MatrixKit/MatrixKit.h>
|
||||
|
||||
@interface GlobalNotificationSettingsViewController : MXKNotificationSettingsViewController
|
||||
|
||||
@end
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
Copyright 2015 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 "GlobalNotificationSettingsViewController.h"
|
||||
|
||||
#import "RageShakeManager.h"
|
||||
|
||||
@implementation GlobalNotificationSettingsViewController
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
// Do any additional setup after loading the view, typically from a nib.
|
||||
|
||||
// Setup `MXKRoomMemberListViewController` properties
|
||||
self.rageShakeManager = [RageShakeManager sharedManager];
|
||||
}
|
||||
@end
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
Copyright 2015 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 <MatrixKit/MatrixKit.h>
|
||||
|
||||
@interface HomeViewController:MXKViewController <UITableViewDataSource, UITableViewDelegate, UISearchBarDelegate, UITextFieldDelegate, MXKRoomCreationViewDelegate>
|
||||
|
||||
@property (weak, nonatomic) IBOutlet UISearchBar *publicRoomsSearchBar;
|
||||
@property (weak, nonatomic) IBOutlet UITableView *tableView;
|
||||
|
||||
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *publicRoomsSearchBarHeightConstraint;
|
||||
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *publicRoomsSearchBarTopConstraint;
|
||||
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *tableViewBottomConstraint;
|
||||
|
||||
/**
|
||||
Add a matrix REST Client. It is used to make Matrix API requests and retrieve public rooms.
|
||||
*/
|
||||
- (void)addRestClient:(MXRestClient*)restClient;
|
||||
|
||||
/**
|
||||
Remove a matrix REST Client.
|
||||
*/
|
||||
- (void)removeRestClient:(MXRestClient*)restClient;
|
||||
|
||||
/**
|
||||
Enable the search in recents list according to the room display name (YES by default).
|
||||
Set NO this property to disable this option and hide the related bar button.
|
||||
*/
|
||||
@property (nonatomic) BOOL enableSearch;
|
||||
|
||||
@end
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
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 <MatrixKit/MatrixKit.h>
|
||||
|
||||
#define TABBAR_HOME_INDEX 0
|
||||
#define TABBAR_RECENTS_INDEX 1
|
||||
#define TABBAR_CONTACTS_INDEX 2
|
||||
#define TABBAR_SETTINGS_INDEX 3
|
||||
#define TABBAR_COUNT 4
|
||||
|
||||
@interface MasterTabBarController : UITabBarController
|
||||
|
||||
// Associated matrix sessions (empty by default).
|
||||
@property (nonatomic, readonly) NSArray *mxSessions;
|
||||
|
||||
// Current selected room id. nil if no room is presently visible.
|
||||
@property (strong, nonatomic) NSString *visibleRoomId;
|
||||
|
||||
// Add a matrix session. This session is propagated to all view controllers handled by the tab bar controller.
|
||||
- (void)addMatrixSession:(MXSession*)mxSession;
|
||||
// Remove a matrix session.
|
||||
- (void)removeMatrixSession:(MXSession*)mxSession;
|
||||
|
||||
- (void)showAuthenticationScreen;
|
||||
- (void)showRoomCreationForm;
|
||||
- (void)showRoom:(NSString*)roomId withMatrixSession:(MXSession*)mxSession;
|
||||
|
||||
- (void)popRoomViewControllerAnimated:(BOOL)animated;
|
||||
|
||||
- (BOOL)isPresentingMediaPicker;
|
||||
- (void)presentMediaPicker:(UIImagePickerController*)mediaPicker;
|
||||
- (void)dismissMediaPicker;
|
||||
|
||||
@end
|
||||
|
||||
@@ -0,0 +1,315 @@
|
||||
/*
|
||||
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 "AppDelegate.h"
|
||||
|
||||
#import "HomeViewController.h"
|
||||
|
||||
#import "RecentsViewController.h"
|
||||
#import "RecentListDataSource.h"
|
||||
|
||||
#import "ContactsViewController.h"
|
||||
|
||||
#import "SettingsViewController.h"
|
||||
|
||||
@interface MasterTabBarController ()
|
||||
{
|
||||
//Array of `MXSession` instances.
|
||||
NSMutableArray *mxSessionArray;
|
||||
|
||||
// Tab bar view controllers
|
||||
HomeViewController *homeViewController;
|
||||
|
||||
UINavigationController *recentsNavigationController;
|
||||
RecentsViewController *recentsViewController;
|
||||
|
||||
ContactsViewController *contactsViewController;
|
||||
|
||||
SettingsViewController *settingsViewController;
|
||||
|
||||
// mediaPicker
|
||||
UIImagePickerController *mediaPicker;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation MasterTabBarController
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
// Do any additional setup after loading the view, typically from a nib.
|
||||
|
||||
mxSessionArray = [NSMutableArray array];
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Retrieve the home view controller
|
||||
UIViewController* home = [self.viewControllers objectAtIndex:TABBAR_HOME_INDEX];
|
||||
if ([home isKindOfClass:[UINavigationController class]])
|
||||
{
|
||||
UINavigationController *homeNavigationController = (UINavigationController*)home;
|
||||
for (UIViewController *viewController in homeNavigationController.viewControllers)
|
||||
{
|
||||
if ([viewController isKindOfClass:[HomeViewController class]])
|
||||
{
|
||||
homeViewController = (HomeViewController*)viewController;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Retrieve the constacts view controller
|
||||
UIViewController* contacts = [self.viewControllers objectAtIndex:TABBAR_CONTACTS_INDEX];
|
||||
if ([contacts isKindOfClass:[UINavigationController class]])
|
||||
{
|
||||
UINavigationController *contactsNavigationController = (UINavigationController*)contacts;
|
||||
for (UIViewController *viewController in contactsNavigationController.viewControllers)
|
||||
{
|
||||
if ([viewController isKindOfClass:[ContactsViewController class]])
|
||||
{
|
||||
contactsViewController = (ContactsViewController*)viewController;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Retrieve the settings view controller
|
||||
UIViewController* settings = [self.viewControllers objectAtIndex:TABBAR_SETTINGS_INDEX];
|
||||
if ([settings isKindOfClass:[UINavigationController class]])
|
||||
{
|
||||
UINavigationController *settingsNavigationController = (UINavigationController*)settings;
|
||||
for (UIViewController *viewController in settingsNavigationController.viewControllers)
|
||||
{
|
||||
if ([viewController isKindOfClass:[SettingsViewController class]])
|
||||
{
|
||||
settingsViewController = (SettingsViewController*)viewController;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sanity check
|
||||
NSAssert(homeViewController &&recentsViewController && contactsViewController && settingsViewController, @"Something wrong in Main.storyboard");
|
||||
}
|
||||
|
||||
- (void)viewDidAppear:(BOOL)animated
|
||||
{
|
||||
[super viewDidAppear:animated];
|
||||
|
||||
// Check whether we're not logged in
|
||||
if (![MXKAccountManager sharedManager].accounts.count)
|
||||
{
|
||||
[self showAuthenticationScreen];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)didReceiveMemoryWarning
|
||||
{
|
||||
[super didReceiveMemoryWarning];
|
||||
|
||||
// Dispose of any resources that can be recreated.
|
||||
[[AppDelegate theDelegate] reloadMatrixSessions:NO];
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
mxSessionArray = nil;
|
||||
|
||||
homeViewController = nil;
|
||||
recentsNavigationController = nil;
|
||||
recentsViewController = nil;
|
||||
contactsViewController = nil;
|
||||
settingsViewController = 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];
|
||||
}
|
||||
}
|
||||
|
||||
[self popRoomViewControllerAnimated:NO];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (NSArray*)mxSessions
|
||||
{
|
||||
return [NSArray arrayWithArray:mxSessionArray];
|
||||
}
|
||||
|
||||
- (void)addMatrixSession:(MXSession *)mxSession
|
||||
{
|
||||
if (mxSession)
|
||||
{
|
||||
// Update recents data source (The recents view controller will be updated by its data source)
|
||||
if (!mxSessionArray.count)
|
||||
{
|
||||
// This is the first added session, list all the recents for the logged user
|
||||
RecentListDataSource *recentlistDataSource = [[RecentListDataSource alloc] initWithMatrixSession:mxSession];
|
||||
[recentsViewController displayList:recentlistDataSource];
|
||||
}
|
||||
else
|
||||
{
|
||||
[recentsViewController.dataSource addMatrixSession:mxSession];
|
||||
}
|
||||
|
||||
// Update home tab
|
||||
[homeViewController addMatrixSession:mxSession];
|
||||
// Update contacts tab
|
||||
[contactsViewController addMatrixSession:mxSession];
|
||||
// Update settings tab
|
||||
[settingsViewController addMatrixSession:mxSession];
|
||||
|
||||
[mxSessionArray addObject:mxSession];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)removeMatrixSession:(MXSession*)mxSession
|
||||
{
|
||||
// Update recents data source
|
||||
[recentsViewController.dataSource removeMatrixSession:mxSession];
|
||||
|
||||
// Update home tab
|
||||
[homeViewController removeMatrixSession:mxSession];
|
||||
// Update contacts tab
|
||||
[contactsViewController removeMatrixSession:mxSession];
|
||||
// Update settings tab
|
||||
[settingsViewController removeMatrixSession:mxSession];
|
||||
|
||||
[mxSessionArray removeObject:mxSession];
|
||||
|
||||
// Check whether there are others sessions
|
||||
if (!mxSessionArray.count)
|
||||
{
|
||||
// Keep reference on existing dataSource to release it properly
|
||||
MXKRecentsDataSource *previousRecentlistDataSource = recentsViewController.dataSource;
|
||||
[recentsViewController displayList:nil];
|
||||
[previousRecentlistDataSource destroy];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)showAuthenticationScreen
|
||||
{
|
||||
[self restoreInitialDisplay];
|
||||
[self performSegueWithIdentifier:@"showAuth" sender:self];
|
||||
}
|
||||
|
||||
- (void)showRoomCreationForm
|
||||
{
|
||||
// Switch in Home Tab
|
||||
[self setSelectedIndex:TABBAR_HOME_INDEX];
|
||||
}
|
||||
|
||||
- (void)showRoom:(NSString*)roomId withMatrixSession:(MXSession*)mxSession
|
||||
{
|
||||
[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 selectRoomWithId:roomId inMatrixSession:mxSession];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)popRoomViewControllerAnimated:(BOOL)animated
|
||||
{
|
||||
// Force back to recents list if room details is displayed in Recents Tab
|
||||
if (recentsViewController)
|
||||
{
|
||||
[recentsNavigationController popToViewController:recentsViewController animated:animated];
|
||||
// Release the current selected room
|
||||
[recentsViewController closeSelectedRoom];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)isPresentingMediaPicker
|
||||
{
|
||||
return nil != mediaPicker;
|
||||
}
|
||||
|
||||
- (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;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setVisibleRoomId:(NSString *)roomId
|
||||
{
|
||||
if (roomId)
|
||||
{
|
||||
// Enable inApp notification for this room in all existing accounts.
|
||||
NSArray *mxAccounts = [MXKAccountManager sharedManager].accounts;
|
||||
for (MXKAccount *account in mxAccounts)
|
||||
{
|
||||
[account updateNotificationListenerForRoomId:roomId ignore:NO];
|
||||
}
|
||||
}
|
||||
|
||||
_visibleRoomId = roomId;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
Copyright 2015 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 <MatrixKit/MatrixKit.h>
|
||||
|
||||
@interface RecentsViewController : MXKRecentListViewController <MXKRecentListViewControllerDelegate, UIGestureRecognizerDelegate>
|
||||
|
||||
/**
|
||||
Open the room with the provided identifier in a specific matrix session.
|
||||
|
||||
@param roomId the room identifier.
|
||||
@param mxSession the matrix session in which the room should be available.
|
||||
*/
|
||||
- (void)selectRoomWithId:(NSString*)roomId inMatrixSession:(MXSession*)mxSession;
|
||||
|
||||
/**
|
||||
Close the current selected room (if any)
|
||||
*/
|
||||
- (void)closeSelectedRoom;
|
||||
|
||||
@end
|
||||
|
||||
@@ -0,0 +1,429 @@
|
||||
/*
|
||||
Copyright 2015 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 "AppDelegate.h"
|
||||
|
||||
#import "RageShakeManager.h"
|
||||
|
||||
#import "NSBundle+MatrixKit.h"
|
||||
|
||||
@interface RecentsViewController ()
|
||||
{
|
||||
|
||||
// Recents refresh handling
|
||||
BOOL shouldScrollToTopOnRefresh;
|
||||
|
||||
// Selected room description
|
||||
NSString *selectedRoomId;
|
||||
MXSession *selectedRoomSession;
|
||||
|
||||
// Keep reference on the current room view controller to release it correctly
|
||||
RoomViewController *currentRoomViewController;
|
||||
|
||||
// Keep the selected cell index to handle correctly split view controller display in landscape mode
|
||||
NSIndexPath *currentSelectedCellIndexPath;
|
||||
|
||||
// "Mark all as read" option
|
||||
UITapGestureRecognizer *navigationBarTapGesture;
|
||||
MXKAlert *markAllAsReadAlert;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation RecentsViewController
|
||||
|
||||
- (void)awakeFromNib
|
||||
{
|
||||
[super awakeFromNib];
|
||||
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad)
|
||||
{
|
||||
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;
|
||||
|
||||
// Add navigation items
|
||||
NSArray *rightBarButtonItems = self.navigationItem.rightBarButtonItems;
|
||||
UIBarButtonItem *addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(createNewRoom:)];
|
||||
self.navigationItem.rightBarButtonItems = rightBarButtonItems ? [rightBarButtonItems arrayByAddingObject:addButton] : @[addButton];
|
||||
|
||||
// Prepare tap gesture on title bar
|
||||
navigationBarTapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onNavigationBarTap:)];
|
||||
[navigationBarTapGesture setNumberOfTouchesRequired:1];
|
||||
[navigationBarTapGesture setNumberOfTapsRequired:1];
|
||||
[navigationBarTapGesture setDelegate:self];
|
||||
|
||||
// Initialisation
|
||||
currentSelectedCellIndexPath = nil;
|
||||
|
||||
// Setup `MXKRecentListViewController` properties
|
||||
self.rageShakeManager = [RageShakeManager sharedManager];
|
||||
|
||||
// The view controller handles itself the selected recent
|
||||
self.delegate = self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[self closeSelectedRoom];
|
||||
}
|
||||
|
||||
- (void)destroy
|
||||
{
|
||||
if (markAllAsReadAlert)
|
||||
|
||||
{
|
||||
[markAllAsReadAlert dismiss:NO];
|
||||
markAllAsReadAlert = nil;
|
||||
}
|
||||
|
||||
if (navigationBarTapGesture)
|
||||
{
|
||||
[self.navigationController.navigationBar removeGestureRecognizer:navigationBarTapGesture];
|
||||
navigationBarTapGesture = nil;
|
||||
}
|
||||
|
||||
[super destroy];
|
||||
}
|
||||
|
||||
- (void)setEditing:(BOOL)editing animated:(BOOL)animated
|
||||
{
|
||||
[super setEditing:editing animated:animated];
|
||||
|
||||
self.recentsTableView.editing = editing;
|
||||
}
|
||||
|
||||
- (void)didReceiveMemoryWarning
|
||||
{
|
||||
[super didReceiveMemoryWarning];
|
||||
// Dispose of any resources that can be recreated.
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated
|
||||
{
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
[self updateNavigationBarTitle];
|
||||
|
||||
// Deselect the current selected row, it will be restored on viewDidAppear (if any)
|
||||
NSIndexPath *indexPath = [self.recentsTableView indexPathForSelectedRow];
|
||||
if (indexPath)
|
||||
{
|
||||
[self.recentsTableView deselectRowAtIndexPath:indexPath animated:NO];
|
||||
}
|
||||
|
||||
[self.navigationController.navigationBar addGestureRecognizer:navigationBarTapGesture];
|
||||
}
|
||||
|
||||
- (void)viewWillDisappear:(BOOL)animated
|
||||
{
|
||||
[super viewWillDisappear:animated];
|
||||
|
||||
// Leave potential editing mode
|
||||
[self setEditing:NO];
|
||||
|
||||
selectedRoomId = nil;
|
||||
selectedRoomSession = nil;
|
||||
|
||||
if (markAllAsReadAlert)
|
||||
{
|
||||
[markAllAsReadAlert dismiss:NO];
|
||||
markAllAsReadAlert = nil;
|
||||
}
|
||||
|
||||
[self.navigationController.navigationBar removeGestureRecognizer:navigationBarTapGesture];
|
||||
}
|
||||
|
||||
- (void)viewDidAppear:(BOOL)animated
|
||||
{
|
||||
[super viewDidAppear:animated];
|
||||
|
||||
// Release the current selected room (if any) except if the Room ViewController is still visible (see splitViewController.isCollapsed condition)
|
||||
if (!self.splitViewController || self.splitViewController.isCollapsed)
|
||||
{
|
||||
// Release the current selected room (if any).
|
||||
[self closeSelectedRoom];
|
||||
}
|
||||
else
|
||||
{
|
||||
// In case of split view controller where the primary and secondary view controllers are displayed side-by-side onscreen,
|
||||
// the selected room (if any) is highlighted.
|
||||
[self refreshCurrentSelectedCell:YES];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (void)selectRoomWithId:(NSString*)roomId inMatrixSession:(MXSession*)matrixSession
|
||||
{
|
||||
if (selectedRoomId && [selectedRoomId isEqualToString:roomId]
|
||||
&& selectedRoomSession && selectedRoomSession == matrixSession)
|
||||
{
|
||||
// Nothing to do
|
||||
return;
|
||||
}
|
||||
|
||||
selectedRoomId = roomId;
|
||||
selectedRoomSession = matrixSession;
|
||||
|
||||
if (roomId && matrixSession)
|
||||
{
|
||||
[self performSegueWithIdentifier:@"showDetails" sender:self];
|
||||
}
|
||||
else
|
||||
{
|
||||
[self closeSelectedRoom];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)closeSelectedRoom
|
||||
{
|
||||
selectedRoomId = nil;
|
||||
selectedRoomSession = nil;
|
||||
|
||||
if (currentRoomViewController)
|
||||
{
|
||||
if (currentRoomViewController.roomDataSource)
|
||||
{
|
||||
// Let the manager release this room data source
|
||||
MXSession *mxSession = currentRoomViewController.roomDataSource.mxSession;
|
||||
MXKRoomDataSourceManager *roomDataSourceManager = [MXKRoomDataSourceManager sharedManagerForMatrixSession:mxSession];
|
||||
[roomDataSourceManager closeRoomDataSource:currentRoomViewController.roomDataSource forceClose:NO];
|
||||
}
|
||||
|
||||
[currentRoomViewController destroy];
|
||||
currentRoomViewController = nil;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Internal methods
|
||||
|
||||
- (void)updateNavigationBarTitle
|
||||
{
|
||||
NSString *title = NSLocalizedStringFromTable(@"recents", @"MatrixConsole", nil);
|
||||
|
||||
if (self.dataSource.unreadCount)
|
||||
{
|
||||
title = [NSString stringWithFormat:@"%@ (%tu)", title, self.dataSource.unreadCount];
|
||||
}
|
||||
self.navigationItem.title = title;
|
||||
}
|
||||
|
||||
- (void)createNewRoom:(id)sender
|
||||
{
|
||||
[[AppDelegate theDelegate].masterTabBarController showRoomCreationForm];
|
||||
}
|
||||
|
||||
- (void)scrollToTop
|
||||
{
|
||||
// stop any scrolling effect
|
||||
[UIView setAnimationsEnabled:NO];
|
||||
// before scrolling to the tableview top
|
||||
self.recentsTableView.contentOffset = CGPointMake(-self.recentsTableView.contentInset.left, -self.recentsTableView.contentInset.top);
|
||||
[UIView setAnimationsEnabled:YES];
|
||||
}
|
||||
|
||||
- (void)refreshCurrentSelectedCell:(BOOL)forceVisible
|
||||
{
|
||||
// Update here the index of the current selected cell (if any) - Useful in landscape mode with split view controller.
|
||||
currentSelectedCellIndexPath = nil;
|
||||
if (currentRoomViewController)
|
||||
{
|
||||
// Restore the current selected room id, it is erased when view controller disappeared (see viewWillDisappear).
|
||||
if (!selectedRoomId)
|
||||
{
|
||||
selectedRoomId = currentRoomViewController.roomDataSource.roomId;
|
||||
selectedRoomSession = currentRoomViewController.mainSession;
|
||||
}
|
||||
|
||||
// Look for the rank of this selected room in displayed recents
|
||||
currentSelectedCellIndexPath = [self.dataSource cellIndexPathWithRoomId:selectedRoomId andMatrixSession:selectedRoomSession];
|
||||
}
|
||||
|
||||
if (currentSelectedCellIndexPath)
|
||||
{
|
||||
// Select the right row
|
||||
[self.recentsTableView selectRowAtIndexPath:currentSelectedCellIndexPath animated:YES scrollPosition:UITableViewScrollPositionNone];
|
||||
|
||||
if (forceVisible)
|
||||
{
|
||||
// Scroll table view to make the selected row appear at second position
|
||||
NSInteger topCellIndexPathRow = currentSelectedCellIndexPath.row ? currentSelectedCellIndexPath.row - 1: currentSelectedCellIndexPath.row;
|
||||
NSIndexPath* indexPath = [NSIndexPath indexPathForRow:topCellIndexPathRow inSection:currentSelectedCellIndexPath.section];
|
||||
[self.recentsTableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionTop animated:NO];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NSIndexPath *indexPath = [self.recentsTableView indexPathForSelectedRow];
|
||||
if (indexPath)
|
||||
{
|
||||
[self.recentsTableView deselectRowAtIndexPath:indexPath animated:NO];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (void)onNavigationBarTap:(id)sender
|
||||
{
|
||||
if (self.dataSource.unreadCount)
|
||||
|
||||
{
|
||||
__weak typeof(self) weakSelf = self;
|
||||
|
||||
markAllAsReadAlert = [[MXKAlert alloc] initWithTitle:NSLocalizedStringFromTable(@"mark_all_as_read_prompt", @"MatrixConsole", nil) message:nil style:MXKAlertStyleAlert];
|
||||
|
||||
markAllAsReadAlert.cancelButtonIndex = [markAllAsReadAlert addActionWithTitle:[NSBundle mxk_localizedStringForKey:@"no"] style:MXKAlertActionStyleDefault handler:^(MXKAlert *alert)
|
||||
{
|
||||
typeof(self) strongSelf = weakSelf;
|
||||
strongSelf->markAllAsReadAlert = nil;
|
||||
}];
|
||||
|
||||
[markAllAsReadAlert addActionWithTitle:[NSBundle mxk_localizedStringForKey:@"yes"] style:MXKAlertActionStyleDefault handler:^(MXKAlert *alert)
|
||||
{
|
||||
typeof(self) strongSelf = weakSelf;
|
||||
|
||||
strongSelf->markAllAsReadAlert = nil;
|
||||
|
||||
[strongSelf.dataSource markAllAsRead];
|
||||
[strongSelf updateNavigationBarTitle];
|
||||
}];
|
||||
|
||||
[markAllAsReadAlert showInViewController:self];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Segues
|
||||
|
||||
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
|
||||
{
|
||||
if ([[segue identifier] isEqualToString:@"showDetails"])
|
||||
{
|
||||
UIViewController *controller;
|
||||
if ([[segue destinationViewController] isKindOfClass:[UINavigationController class]])
|
||||
{
|
||||
controller = [[segue destinationViewController] topViewController];
|
||||
}
|
||||
else
|
||||
{
|
||||
controller = [segue destinationViewController];
|
||||
}
|
||||
|
||||
if ([controller isKindOfClass:[RoomViewController class]])
|
||||
{
|
||||
// Release existing Room view controller (if any)
|
||||
if (currentRoomViewController)
|
||||
{
|
||||
if (currentRoomViewController.roomDataSource)
|
||||
{
|
||||
// Let the manager release this room data source
|
||||
MXSession *mxSession = currentRoomViewController.roomDataSource.mxSession;
|
||||
MXKRoomDataSourceManager *roomDataSourceManager = [MXKRoomDataSourceManager sharedManagerForMatrixSession:mxSession];
|
||||
[roomDataSourceManager closeRoomDataSource:currentRoomViewController.roomDataSource forceClose:NO];
|
||||
}
|
||||
|
||||
[currentRoomViewController destroy];
|
||||
currentRoomViewController = nil;
|
||||
}
|
||||
|
||||
currentRoomViewController = (RoomViewController *)controller;
|
||||
|
||||
MXKRoomDataSourceManager *roomDataSourceManager = [MXKRoomDataSourceManager sharedManagerForMatrixSession:selectedRoomSession];
|
||||
MXKRoomDataSource *roomDataSource = [roomDataSourceManager roomDataSourceForRoom:selectedRoomId create:YES];
|
||||
[currentRoomViewController displayRoom:roomDataSource];
|
||||
}
|
||||
|
||||
// Reset unread count for this room
|
||||
//[roomDataSource resetUnreadCount]; // @TODO: This automatically done by roomDataSource. Is it a good thing?
|
||||
[self updateNavigationBarTitle];
|
||||
|
||||
if (self.splitViewController)
|
||||
{
|
||||
// Refresh selected cell without scrolling the selected cell (We suppose it's visible here)
|
||||
[self refreshCurrentSelectedCell:NO];
|
||||
|
||||
// IOS >= 8
|
||||
if ([self.splitViewController respondsToSelector:@selector(displayModeButtonItem)])
|
||||
{
|
||||
controller.navigationItem.leftBarButtonItem = self.splitViewController.displayModeButtonItem;
|
||||
}
|
||||
|
||||
//
|
||||
controller.navigationItem.leftItemsSupplementBackButton = YES;
|
||||
}
|
||||
|
||||
// Hide back button title
|
||||
self.navigationItem.backBarButtonItem =[[UIBarButtonItem alloc] initWithTitle:@"" style:UIBarButtonItemStylePlain target:nil action:nil];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - MXKDataSourceDelegate
|
||||
- (void)dataSource:(MXKDataSource *)dataSource didCellChange:(id)changes
|
||||
{
|
||||
// Update the unreadCount in the title
|
||||
[self updateNavigationBarTitle];
|
||||
|
||||
[self.recentsTableView reloadData];
|
||||
|
||||
if (shouldScrollToTopOnRefresh)
|
||||
{
|
||||
[self scrollToTop];
|
||||
shouldScrollToTopOnRefresh = NO;
|
||||
}
|
||||
|
||||
// In case of split view controller where the primary and secondary view controllers are displayed side-by-side onscreen,
|
||||
// the selected room (if any) is updated and kept visible.
|
||||
if (self.splitViewController && !self.splitViewController.isCollapsed)
|
||||
{
|
||||
[self refreshCurrentSelectedCell:YES];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - MXKRecentListViewControllerDelegate
|
||||
- (void)recentListViewController:(MXKRecentListViewController *)recentListViewController didSelectRoom:(NSString *)roomId inMatrixSession:(MXSession *)matrixSession
|
||||
{
|
||||
// Open the room
|
||||
[self selectRoomWithId:roomId inMatrixSession:matrixSession];
|
||||
}
|
||||
|
||||
#pragma mark - Override UISearchBarDelegate
|
||||
|
||||
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
|
||||
{
|
||||
// Prepare table refresh on new search session
|
||||
shouldScrollToTopOnRefresh = YES;
|
||||
|
||||
[super searchBar:searchBar textDidChange:searchText];
|
||||
}
|
||||
|
||||
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar
|
||||
{
|
||||
// Prepare table refresh on end of search
|
||||
shouldScrollToTopOnRefresh = YES;
|
||||
|
||||
[super searchBarCancelButtonClicked: searchBar];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
Copyright 2015 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 <MatrixKit/MatrixKit.h>
|
||||
|
||||
@interface RoomMembersViewController : MXKRoomMemberListViewController <MXKRoomMemberListViewControllerDelegate>
|
||||
|
||||
@end
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
Copyright 2015 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 "RoomMembersViewController.h"
|
||||
|
||||
#import "AppDelegate.h"
|
||||
#import "RageShakeManager.h"
|
||||
|
||||
@interface RoomMembersViewController ()
|
||||
{
|
||||
/**
|
||||
The selected member
|
||||
*/
|
||||
MXRoomMember *selectedMember;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation RoomMembersViewController
|
||||
|
||||
- (void)awakeFromNib
|
||||
{
|
||||
[super awakeFromNib];
|
||||
|
||||
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad)
|
||||
{
|
||||
self.preferredContentSize = CGSizeMake(320.0, 600.0);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
|
||||
// Setup `MXKRoomMemberListViewController` properties
|
||||
self.rageShakeManager = [RageShakeManager sharedManager];
|
||||
|
||||
// The view controller handles itself the selected roomMember
|
||||
self.delegate = self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
selectedMember = nil;
|
||||
}
|
||||
|
||||
- (void)didReceiveMemoryWarning
|
||||
{
|
||||
[super didReceiveMemoryWarning];
|
||||
// Dispose of any resources that can be recreated.
|
||||
}
|
||||
|
||||
#pragma mark - Segues
|
||||
|
||||
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
|
||||
{
|
||||
// Keep ref on destinationViewController
|
||||
[super prepareForSegue:segue sender:sender];
|
||||
|
||||
if ([[segue identifier] isEqualToString:@"showDetails"])
|
||||
{
|
||||
if (selectedMember)
|
||||
{
|
||||
MXKRoomMemberDetailsViewController *memberViewController = segue.destinationViewController;
|
||||
// Set rageShake handler
|
||||
memberViewController.rageShakeManager = [RageShakeManager sharedManager];
|
||||
// Set delegate to handle start chat option
|
||||
memberViewController.delegate = [AppDelegate theDelegate];
|
||||
|
||||
[memberViewController displayRoomMember:selectedMember withMatrixRoom:[self.mainSession roomWithRoomId:self.dataSource.roomId]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - MXKRoomMemberListViewControllerDelegate
|
||||
- (void)roomMemberListViewController:(MXKRoomMemberListViewController *)roomMemberListViewController didSelectMember:(MXRoomMember *)member
|
||||
{
|
||||
// Report the selected member and open details view
|
||||
selectedMember = member;
|
||||
[self performSegueWithIdentifier:@"showDetails" sender:self];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -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 <MatrixKit/MatrixKit.h>
|
||||
|
||||
@interface RoomViewController : MXKRoomViewController
|
||||
|
||||
@end
|
||||
|
||||
@@ -0,0 +1,346 @@
|
||||
/*
|
||||
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 "RoomViewController.h"
|
||||
|
||||
#import "MXKRoomBubbleTableViewCell.h"
|
||||
|
||||
#import "AppDelegate.h"
|
||||
|
||||
#import "RageShakeManager.h"
|
||||
|
||||
@interface RoomViewController ()
|
||||
{
|
||||
// Members list
|
||||
id membersListener;
|
||||
|
||||
// Voip call options
|
||||
UIButton *voipVoiceCallButton;
|
||||
UIButton *voipVideoCallButton;
|
||||
UIBarButtonItem *voipVoiceCallBarButtonItem;
|
||||
UIBarButtonItem *voipVideoCallBarButtonItem;
|
||||
|
||||
// the user taps on a member thumbnail
|
||||
MXRoomMember *selectedRoomMember;
|
||||
}
|
||||
|
||||
@property (strong, nonatomic) IBOutlet UIBarButtonItem *showRoomMembersButtonItem;
|
||||
|
||||
@property (strong, nonatomic) MXKAlert *actionMenu;
|
||||
|
||||
@end
|
||||
|
||||
@implementation RoomViewController
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
|
||||
// Set room title view
|
||||
[self setRoomTitleViewClass:MXKRoomTitleViewWithTopic.class];
|
||||
|
||||
// Replace the default input toolbar view with the one based on `HPGrowingTextView`.
|
||||
[self setRoomInputToolbarViewClass:MXKRoomInputToolbarViewWithHPGrowingText.class];
|
||||
|
||||
// Set rageShake handler
|
||||
self.rageShakeManager = [RageShakeManager sharedManager];
|
||||
}
|
||||
|
||||
- (void)didReceiveMemoryWarning
|
||||
{
|
||||
[super didReceiveMemoryWarning];
|
||||
// Dispose of any resources that can be recreated.
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated
|
||||
{
|
||||
[super viewWillAppear:animated];
|
||||
}
|
||||
|
||||
- (void)viewWillDisappear:(BOOL)animated
|
||||
{
|
||||
[super viewWillDisappear:animated];
|
||||
|
||||
// hide action
|
||||
if (self.actionMenu)
|
||||
{
|
||||
[self.actionMenu dismiss:NO];
|
||||
self.actionMenu = nil;
|
||||
}
|
||||
|
||||
if (self.roomDataSource)
|
||||
{
|
||||
if (membersListener)
|
||||
{
|
||||
[self.roomDataSource.room removeListener:membersListener];
|
||||
membersListener = nil;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)viewDidAppear:(BOOL)animated
|
||||
{
|
||||
if (self.childViewControllers)
|
||||
{
|
||||
// Dispose data source defined for room member list view controller (if any)
|
||||
for (id childViewController in self.childViewControllers)
|
||||
{
|
||||
if ([childViewController isKindOfClass:[MXKRoomMemberListViewController class]])
|
||||
{
|
||||
MXKRoomMemberListViewController *viewController = (MXKRoomMemberListViewController*)childViewController;
|
||||
MXKDataSource *dataSource = [viewController dataSource];
|
||||
[viewController destroy];
|
||||
[dataSource destroy];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[super viewDidAppear:animated];
|
||||
|
||||
if (self.roomDataSource)
|
||||
{
|
||||
// Set visible room id
|
||||
[AppDelegate theDelegate].masterTabBarController.visibleRoomId = self.roomDataSource.roomId;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)viewDidDisappear:(BOOL)animated
|
||||
{
|
||||
[super viewDidDisappear:animated];
|
||||
|
||||
// Reset visible room id
|
||||
[AppDelegate theDelegate].masterTabBarController.visibleRoomId = nil;
|
||||
}
|
||||
|
||||
#pragma mark - Override MXKRoomViewController
|
||||
|
||||
- (void)displayRoom:(MXKRoomDataSource *)dataSource
|
||||
{
|
||||
// Remove members listener (if any) before changing dataSource.
|
||||
if (membersListener)
|
||||
{
|
||||
[self.roomDataSource.room removeListener:membersListener];
|
||||
membersListener = nil;
|
||||
}
|
||||
|
||||
[super displayRoom:dataSource];
|
||||
}
|
||||
|
||||
- (void)updateViewControllerAppearanceOnRoomDataSourceState
|
||||
{
|
||||
[super updateViewControllerAppearanceOnRoomDataSourceState];
|
||||
|
||||
// Update UI by considering dataSource state
|
||||
if (self.roomDataSource && self.roomDataSource.state == MXKDataSourceStateReady)
|
||||
{
|
||||
// Register a listener for events that concern room members
|
||||
if (!membersListener)
|
||||
{
|
||||
membersListener = [self.roomDataSource.room listenToEventsOfTypes:@[kMXEventTypeStringRoomMember] onEvent:^(MXEvent *event, MXEventDirection direction, id customObject) {
|
||||
|
||||
// Consider only live event
|
||||
if (direction == MXEventDirectionForwards)
|
||||
{
|
||||
// Update navigation bar items
|
||||
[self updateNavigationBarButtonItems];
|
||||
}
|
||||
}];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Remove members listener if any.
|
||||
if (membersListener)
|
||||
{
|
||||
[self.roomDataSource.room removeListener:membersListener];
|
||||
membersListener = nil;
|
||||
}
|
||||
}
|
||||
|
||||
// Update navigation bar items
|
||||
[self updateNavigationBarButtonItems];
|
||||
}
|
||||
|
||||
- (BOOL)isIRCStyleCommand:(NSString*)string
|
||||
{
|
||||
// Override the default behavior for `/join` command in order to open automatically the joined room
|
||||
|
||||
if ([string hasPrefix:kCmdJoinRoom])
|
||||
{
|
||||
// Join a room
|
||||
NSString *roomAlias = [string substringFromIndex:kCmdJoinRoom.length + 1];
|
||||
// Remove white space from both ends
|
||||
roomAlias = [roomAlias stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
|
||||
|
||||
// Check
|
||||
if (roomAlias.length)
|
||||
{
|
||||
[self.mainSession joinRoom:roomAlias success:^(MXRoom *room)
|
||||
{
|
||||
// Show the room
|
||||
[[AppDelegate theDelegate].masterTabBarController showRoom:room.state.roomId withMatrixSession:self.mainSession];
|
||||
} failure:^(NSError *error)
|
||||
{
|
||||
NSLog(@"[Console RoomVC] Join roomAlias (%@) failed: %@", roomAlias, error);
|
||||
//Alert user
|
||||
[[AppDelegate theDelegate] showErrorAsAlert:error];
|
||||
}];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Display cmd usage in text input as placeholder
|
||||
self.inputToolbarView.placeholder = @"Usage: /join <room_alias>";
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
return [super isIRCStyleCommand:string];
|
||||
}
|
||||
|
||||
- (void)destroy
|
||||
{
|
||||
if (membersListener)
|
||||
{
|
||||
[self.roomDataSource.room removeListener:membersListener];
|
||||
membersListener = nil;
|
||||
}
|
||||
|
||||
if (self.actionMenu)
|
||||
{
|
||||
[self.actionMenu dismiss:NO];
|
||||
self.actionMenu = nil;
|
||||
}
|
||||
|
||||
[super destroy];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (void)updateNavigationBarButtonItems
|
||||
{
|
||||
// Update navigation bar buttons according to room members count
|
||||
if (self.roomDataSource && self.roomDataSource.state == MXKDataSourceStateReady)
|
||||
{
|
||||
// Check conditions to display voip call buttons
|
||||
if (self.roomDataSource.room.state.members.count == 2 && self.mainSession.callManager)
|
||||
{
|
||||
if (!voipVoiceCallBarButtonItem || !voipVideoCallBarButtonItem)
|
||||
{
|
||||
voipVoiceCallButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
voipVoiceCallButton.frame = CGRectMake(0, 0, 36, 36);
|
||||
UIImage *voiceImage = [UIImage imageNamed:@"voice"];
|
||||
[voipVoiceCallButton setImage:voiceImage forState:UIControlStateNormal];
|
||||
[voipVoiceCallButton setImage:voiceImage forState:UIControlStateHighlighted];
|
||||
[voipVoiceCallButton addTarget:self action:@selector(onButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
|
||||
voipVoiceCallBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:voipVoiceCallButton];
|
||||
|
||||
voipVideoCallButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
voipVideoCallButton.frame = CGRectMake(0, 0, 36, 36);
|
||||
UIImage *videoImage = [UIImage imageNamed:@"video"];
|
||||
[voipVideoCallButton setImage:videoImage forState:UIControlStateNormal];
|
||||
[voipVideoCallButton setImage:videoImage forState:UIControlStateHighlighted];
|
||||
[voipVideoCallButton addTarget:self action:@selector(onButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
|
||||
voipVideoCallBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:voipVideoCallButton];
|
||||
}
|
||||
|
||||
_showRoomMembersButtonItem.enabled = YES;
|
||||
|
||||
self.navigationItem.rightBarButtonItems = @[_showRoomMembersButtonItem, voipVideoCallBarButtonItem, voipVoiceCallBarButtonItem];
|
||||
}
|
||||
else
|
||||
{
|
||||
_showRoomMembersButtonItem.enabled = ([self.roomDataSource.room.state members].count != 0);
|
||||
self.navigationItem.rightBarButtonItems = @[_showRoomMembersButtonItem];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_showRoomMembersButtonItem.enabled = NO;
|
||||
self.navigationItem.rightBarButtonItems = @[_showRoomMembersButtonItem];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - MXKDataSource delegate
|
||||
|
||||
- (void)dataSource:(MXKDataSource *)dataSource didRecognizeAction:(NSString *)actionIdentifier inCell:(id<MXKCellRendering>)cell userInfo:(NSDictionary *)userInfo
|
||||
{
|
||||
// Override default implementation in case of tap on avatar
|
||||
if ([actionIdentifier isEqualToString:kMXKRoomBubbleCellTapOnAvatarView])
|
||||
{
|
||||
selectedRoomMember = [self.roomDataSource.room.state memberWithUserId:userInfo[kMXKRoomBubbleCellUserIdKey]];
|
||||
if (selectedRoomMember)
|
||||
{
|
||||
[self performSegueWithIdentifier:@"showMemberDetails" sender:self];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Keep default implementation for other actions
|
||||
[super dataSource:dataSource didRecognizeAction:actionIdentifier inCell:cell userInfo:userInfo];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Segues
|
||||
|
||||
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
|
||||
{
|
||||
// Keep ref on destinationViewController
|
||||
[super prepareForSegue:segue sender:sender];
|
||||
|
||||
id pushedViewController = [segue destinationViewController];
|
||||
|
||||
if ([[segue identifier] isEqualToString:@"showMemberList"])
|
||||
{
|
||||
if ([pushedViewController isKindOfClass:[MXKRoomMemberListViewController class]])
|
||||
{
|
||||
MXKRoomMemberListViewController* membersController = (MXKRoomMemberListViewController*)pushedViewController;
|
||||
|
||||
// Dismiss keyboard
|
||||
[self dismissKeyboard];
|
||||
|
||||
MXKRoomMemberListDataSource *membersDataSource = [[MXKRoomMemberListDataSource alloc] initWithRoomId:self.roomDataSource.roomId andMatrixSession:self.mainSession];
|
||||
[membersController displayList:membersDataSource];
|
||||
}
|
||||
}
|
||||
else if ([[segue identifier] isEqualToString:@"showMemberDetails"])
|
||||
{
|
||||
if (selectedRoomMember)
|
||||
{
|
||||
MXKRoomMemberDetailsViewController *memberViewController = pushedViewController;
|
||||
// Set rageShake handler
|
||||
memberViewController.rageShakeManager = [RageShakeManager sharedManager];
|
||||
// Set delegate to handle start chat option
|
||||
memberViewController.delegate = [AppDelegate theDelegate];
|
||||
|
||||
[memberViewController displayRoomMember:selectedRoomMember withMatrixRoom:self.roomDataSource.room];
|
||||
|
||||
selectedRoomMember = nil;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Action
|
||||
|
||||
- (IBAction)onButtonPressed:(id)sender
|
||||
{
|
||||
if (sender == voipVoiceCallButton || sender == voipVideoCallButton)
|
||||
{
|
||||
[self.mainSession.callManager placeCallInRoom:self.roomDataSource.roomId withVideo:(sender == voipVideoCallButton)];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
Copyright 2015 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 <MatrixKit/MatrixKit.h>
|
||||
|
||||
@interface SettingsViewController : MXKTableViewController <UIPickerViewDataSource, UIPickerViewDelegate>
|
||||
|
||||
/**
|
||||
The application settings displayed in the view controller.
|
||||
By default the shared application settings are considered.
|
||||
*/
|
||||
@property (nonatomic) MXKAppSettings *settings;
|
||||
|
||||
@end
|
||||
|
||||
@@ -0,0 +1,811 @@
|
||||
/*
|
||||
Copyright 2015 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 "RageShakeManager.h"
|
||||
|
||||
#import "AppDelegate.h"
|
||||
|
||||
#define SETTINGS_SECTION_ACCOUNTS_INDEX 0
|
||||
#define SETTINGS_SECTION_CONTACTS_INDEX 1
|
||||
#define SETTINGS_SECTION_ROOMS_INDEX 2
|
||||
#define SETTINGS_SECTION_CONFIGURATION_INDEX 3
|
||||
#define SETTINGS_SECTION_COMMANDS_INDEX 4
|
||||
#define SETTINGS_SECTION_COUNT 5
|
||||
|
||||
#define SETTINGS_SECTION_ROOMS_DISPLAY_ALL_EVENTS_INDEX 0
|
||||
#define SETTINGS_SECTION_ROOMS_SHOW_REDACTIONS_INDEX 1
|
||||
#define SETTINGS_SECTION_ROOMS_SHOW_UNSUPPORTED_EVENTS_INDEX 2
|
||||
#define SETTINGS_SECTION_ROOMS_SORT_MEMBERS_INDEX 3
|
||||
#define SETTINGS_SECTION_ROOMS_DISPLAY_LEFT_MEMBERS_INDEX 4
|
||||
#define SETTINGS_SECTION_ROOMS_SET_CACHE_SIZE_INDEX 5
|
||||
#define SETTINGS_SECTION_ROOMS_CLEAR_CACHE_INDEX 6
|
||||
#define SETTINGS_SECTION_ROOMS_INDEX_COUNT 7
|
||||
|
||||
@interface SettingsViewController ()
|
||||
{
|
||||
MXKAccount *selectedAccount;
|
||||
id removedAccountObserver;
|
||||
id accountUserInfoObserver;
|
||||
|
||||
// Contacts
|
||||
UISwitch *contactsSyncSwitch;
|
||||
// Country codes management
|
||||
NSArray* countryCodes;
|
||||
NSString* countryCode;
|
||||
NSString* selectedCountryCode;
|
||||
BOOL isSelectingCountryCode;
|
||||
// Dynamic rows in Contacts section
|
||||
NSInteger syncLocalContactsRowIndex;
|
||||
NSInteger countryCodeRowIndex;
|
||||
|
||||
// Rooms settings
|
||||
UISwitch *allEventsSwitch;
|
||||
UISwitch *redactionsSwitch;
|
||||
UISwitch *unsupportedEventsSwitch;
|
||||
UISwitch *sortMembersSwitch;
|
||||
UISwitch *displayLeftMembersSwitch;
|
||||
MXKTableViewCellWithLabelAndSlider* maxCacheSizeCell;
|
||||
NSUInteger minimumCacheSize;
|
||||
UIButton *clearCacheButton;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation SettingsViewController
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
// Do any additional setup after loading the view, typically from a nib.
|
||||
|
||||
// Consider the standard settings by default
|
||||
_settings = [MXKAppSettings standardAppSettings];
|
||||
|
||||
// Initialize the minimum cache size with the current value
|
||||
minimumCacheSize = self.minCachesSize;
|
||||
|
||||
// country selection
|
||||
NSString *path = [[NSBundle mainBundle] pathForResource:@"countryCodes" ofType:@"plist"];
|
||||
countryCodes = [NSArray arrayWithContentsOfFile:path];
|
||||
isSelectingCountryCode = NO;
|
||||
|
||||
// Setup `MXKRoomMemberListViewController` properties
|
||||
self.rageShakeManager = [RageShakeManager sharedManager];
|
||||
|
||||
// Add observer to handle removed accounts
|
||||
removedAccountObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXKAccountManagerDidRemoveAccountNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
|
||||
|
||||
MXKAccount *account = notif.object;
|
||||
if (account)
|
||||
{
|
||||
if (self.childViewControllers.count)
|
||||
{
|
||||
for (id viewController in self.childViewControllers)
|
||||
{
|
||||
// Check whether details of this account was displayed
|
||||
if ([viewController isKindOfClass:[MXKAccountDetailsViewController class]])
|
||||
{
|
||||
MXKAccountDetailsViewController *accountDetailsViewController = viewController;
|
||||
if ([accountDetailsViewController.mxAccount.mxCredentials.userId isEqualToString:account.mxCredentials.userId])
|
||||
{
|
||||
// pop the account details view controller
|
||||
[self.navigationController popToRootViewControllerAnimated:YES];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Refresh table to remove this account
|
||||
[self.tableView reloadData];
|
||||
}];
|
||||
|
||||
// Add observer to handle accounts update
|
||||
accountUserInfoObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXKAccountUserInfoDidChangeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
|
||||
|
||||
// Refresh table to remove this account
|
||||
[self.tableView reloadData];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)didReceiveMemoryWarning
|
||||
{
|
||||
[super didReceiveMemoryWarning];
|
||||
// Dispose of any resources that can be recreated.
|
||||
}
|
||||
|
||||
- (void)destroy
|
||||
{
|
||||
[self reset];
|
||||
|
||||
[super destroy];
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated
|
||||
{
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
if (!_settings)
|
||||
{
|
||||
// Consider the standard settings by default
|
||||
_settings = [MXKAppSettings standardAppSettings];
|
||||
}
|
||||
|
||||
selectedCountryCode = countryCode = [_settings phonebookCountryCode];
|
||||
|
||||
// Update the minimum cache size with the current value
|
||||
// Dispatch this operation to not freeze the app
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
minimumCacheSize = self.minCachesSize;
|
||||
});
|
||||
|
||||
// Refresh display
|
||||
[self.tableView reloadData];
|
||||
}
|
||||
|
||||
- (void)viewWillDisappear:(BOOL)animated
|
||||
{
|
||||
[super viewWillDisappear:animated];
|
||||
|
||||
// if country has been updated
|
||||
// update the contact phonenumbers
|
||||
// and check if they match now to Matrix Users
|
||||
if (![countryCode isEqualToString:selectedCountryCode])
|
||||
{
|
||||
|
||||
[_settings setPhonebookCountryCode:selectedCountryCode];
|
||||
countryCode = selectedCountryCode;
|
||||
}
|
||||
|
||||
countryCode = [_settings phonebookCountryCode];
|
||||
}
|
||||
|
||||
#pragma mark - Internal methods
|
||||
|
||||
- (void)reset
|
||||
{
|
||||
// Remove observers
|
||||
if (removedAccountObserver)
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:removedAccountObserver];
|
||||
removedAccountObserver = nil;
|
||||
}
|
||||
|
||||
if (accountUserInfoObserver)
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:accountUserInfoObserver];
|
||||
accountUserInfoObserver = nil;
|
||||
}
|
||||
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
|
||||
selectedAccount = nil;
|
||||
|
||||
contactsSyncSwitch = nil;
|
||||
|
||||
allEventsSwitch = nil;
|
||||
redactionsSwitch = nil;
|
||||
unsupportedEventsSwitch = nil;
|
||||
sortMembersSwitch = nil;
|
||||
displayLeftMembersSwitch = nil;
|
||||
maxCacheSizeCell = nil;
|
||||
clearCacheButton = nil;
|
||||
}
|
||||
|
||||
- (IBAction)onAccountToggleChange:(id)sender
|
||||
{
|
||||
UISwitch *accountSwitchToggle = sender;
|
||||
|
||||
NSArray *accounts = [[MXKAccountManager sharedManager] accounts];
|
||||
if (accountSwitchToggle.tag < accounts.count)
|
||||
{
|
||||
MXKAccount *account = [accounts objectAtIndex:accountSwitchToggle.tag];
|
||||
account.disabled = !accountSwitchToggle.on;
|
||||
}
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self.tableView reloadData];
|
||||
});
|
||||
}
|
||||
|
||||
#pragma mark - Actions
|
||||
|
||||
- (IBAction)addAccount:(id)sender
|
||||
{
|
||||
[self performSegueWithIdentifier:@"addAccount" sender:self];
|
||||
}
|
||||
|
||||
- (IBAction)logout:(id)sender
|
||||
{
|
||||
[[AppDelegate theDelegate] logout];
|
||||
}
|
||||
|
||||
- (IBAction)onButtonPressed:(id)sender
|
||||
{
|
||||
if (sender == allEventsSwitch)
|
||||
{
|
||||
_settings.showAllEventsInRoomHistory = allEventsSwitch.on;
|
||||
}
|
||||
else if (sender == redactionsSwitch)
|
||||
{
|
||||
_settings.showRedactionsInRoomHistory = redactionsSwitch.on;
|
||||
}
|
||||
else if (sender == unsupportedEventsSwitch)
|
||||
{
|
||||
_settings.showUnsupportedEventsInRoomHistory = unsupportedEventsSwitch.on;
|
||||
}
|
||||
else if (sender == sortMembersSwitch)
|
||||
{
|
||||
_settings.sortRoomMembersUsingLastSeenTime = sortMembersSwitch.on;
|
||||
}
|
||||
else if (sender == displayLeftMembersSwitch)
|
||||
{
|
||||
_settings.showLeftMembersInRoomMemberList = displayLeftMembersSwitch.on;
|
||||
}
|
||||
else if (sender == contactsSyncSwitch)
|
||||
{
|
||||
_settings.syncLocalContacts = contactsSyncSwitch.on;
|
||||
isSelectingCountryCode = NO;
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self.tableView reloadData];
|
||||
});
|
||||
}
|
||||
else if (sender == clearCacheButton)
|
||||
{
|
||||
[[AppDelegate theDelegate] reloadMatrixSessions:YES];
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)onSliderValueChange:(id)sender
|
||||
{
|
||||
if (sender == maxCacheSizeCell.mxkSlider)
|
||||
{
|
||||
UISlider* slider = maxCacheSizeCell.mxkSlider;
|
||||
|
||||
// check if the upper bounds have been updated
|
||||
if (slider.maximumValue != self.maxAllowedCachesSize)
|
||||
{
|
||||
slider.maximumValue = self.maxAllowedCachesSize;
|
||||
}
|
||||
|
||||
// check if the value does not exceed the bounds
|
||||
if (slider.value < minimumCacheSize)
|
||||
{
|
||||
slider.value = minimumCacheSize;
|
||||
}
|
||||
|
||||
[self setCurrentMaxCachesSize:slider.value];
|
||||
|
||||
maxCacheSizeCell.mxkLabel.text = [NSString stringWithFormat:NSLocalizedStringFromTable(@"settings_max_cache_size", @"MatrixConsole", nil), [NSByteCountFormatter stringFromByteCount:self.currentMaxCachesSize countStyle:NSByteCountFormatterCountStyleFile]];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Segues
|
||||
|
||||
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
|
||||
{
|
||||
// Keep ref on destinationViewController
|
||||
[super prepareForSegue:segue sender:sender];
|
||||
|
||||
if ([[segue identifier] isEqualToString:@"showAccountDetails"])
|
||||
{
|
||||
MXKAccountDetailsViewController *accountViewController = segue.destinationViewController;
|
||||
accountViewController.mxAccount = selectedAccount;
|
||||
selectedAccount = nil;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - UITableView data source
|
||||
|
||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
|
||||
{
|
||||
return SETTINGS_SECTION_COUNT;
|
||||
}
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
|
||||
{
|
||||
NSInteger count = 0;
|
||||
if (section == SETTINGS_SECTION_ACCOUNTS_INDEX)
|
||||
{
|
||||
count = [[MXKAccountManager sharedManager] accounts].count + 1; // Add one cell in this section to display "logout all" option.
|
||||
}
|
||||
else if (section == SETTINGS_SECTION_CONTACTS_INDEX)
|
||||
{
|
||||
countryCodeRowIndex = syncLocalContactsRowIndex = -1;
|
||||
|
||||
// init row index
|
||||
syncLocalContactsRowIndex = count++;
|
||||
if ([_settings syncLocalContacts])
|
||||
{
|
||||
countryCodeRowIndex = count++;
|
||||
}
|
||||
}
|
||||
else if (section == SETTINGS_SECTION_ROOMS_INDEX)
|
||||
{
|
||||
count = SETTINGS_SECTION_ROOMS_INDEX_COUNT;
|
||||
}
|
||||
else if (section == SETTINGS_SECTION_CONFIGURATION_INDEX)
|
||||
{
|
||||
count = 1;
|
||||
}
|
||||
else if (section == SETTINGS_SECTION_COMMANDS_INDEX)
|
||||
{
|
||||
count = 1;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
UITableViewCell *cell = nil;
|
||||
|
||||
if (indexPath.section == SETTINGS_SECTION_ACCOUNTS_INDEX)
|
||||
{
|
||||
NSArray *accounts = [[MXKAccountManager sharedManager] accounts];
|
||||
if (indexPath.row < accounts.count)
|
||||
{
|
||||
MXKAccountTableViewCell *accountCell = [tableView dequeueReusableCellWithIdentifier:[MXKAccountTableViewCell defaultReuseIdentifier]];
|
||||
if (!accountCell)
|
||||
{
|
||||
accountCell = [[MXKAccountTableViewCell alloc] init];
|
||||
}
|
||||
|
||||
accountCell.mxAccount = [accounts objectAtIndex:indexPath.row];
|
||||
|
||||
// Display switch toggle in case of multiple accounts
|
||||
if (accounts.count > 1 || accountCell.mxAccount.disabled)
|
||||
{
|
||||
accountCell.accountSwitchToggle.tag = indexPath.row;
|
||||
accountCell.accountSwitchToggle.hidden = NO;
|
||||
[accountCell.accountSwitchToggle addTarget:self action:@selector(onAccountToggleChange:) forControlEvents:UIControlEventValueChanged];
|
||||
}
|
||||
|
||||
cell = accountCell;
|
||||
}
|
||||
else
|
||||
{
|
||||
MXKTableViewCellWithButton *logoutBtnCell = [tableView dequeueReusableCellWithIdentifier:[MXKTableViewCellWithButton defaultReuseIdentifier]];
|
||||
if (!logoutBtnCell)
|
||||
{
|
||||
logoutBtnCell = [[MXKTableViewCellWithButton alloc] init];
|
||||
}
|
||||
[logoutBtnCell.mxkButton setTitle:NSLocalizedStringFromTable(@"account_logout_all", @"MatrixConsole", nil) forState:UIControlStateNormal];
|
||||
[logoutBtnCell.mxkButton setTitle:NSLocalizedStringFromTable(@"account_logout_all", @"MatrixConsole", nil) forState:UIControlStateHighlighted];
|
||||
|
||||
[logoutBtnCell.mxkButton removeTarget:self action:nil forControlEvents:UIControlEventTouchUpInside];
|
||||
[logoutBtnCell.mxkButton addTarget:self action:@selector(logout:) forControlEvents:UIControlEventTouchUpInside];
|
||||
|
||||
cell = logoutBtnCell;
|
||||
}
|
||||
}
|
||||
else if (indexPath.section == SETTINGS_SECTION_CONTACTS_INDEX)
|
||||
{
|
||||
if (indexPath.row == syncLocalContactsRowIndex)
|
||||
{
|
||||
MXKTableViewCellWithLabelAndSwitch *contactsCell = [tableView dequeueReusableCellWithIdentifier:[MXKTableViewCellWithLabelAndSwitch defaultReuseIdentifier]];
|
||||
if (!contactsCell)
|
||||
{
|
||||
contactsCell = [[MXKTableViewCellWithLabelAndSwitch alloc] init];
|
||||
}
|
||||
|
||||
[contactsCell.mxkSwitch addTarget:self action:@selector(onButtonPressed:) forControlEvents:UIControlEventValueChanged];
|
||||
|
||||
contactsCell.mxkLabel.text = NSLocalizedStringFromTable(@"settings_contact_sync", @"MatrixConsole", nil);
|
||||
contactsCell.mxkSwitch.on = [_settings syncLocalContacts];
|
||||
contactsSyncSwitch = contactsCell.mxkSwitch;
|
||||
cell = contactsCell;
|
||||
}
|
||||
else if (indexPath.row == countryCodeRowIndex)
|
||||
{
|
||||
int index = 0;
|
||||
NSString* countryName = @"";
|
||||
|
||||
for(NSDictionary* dict in countryCodes)
|
||||
{
|
||||
if ([[dict valueForKey:@"id"] isEqualToString:selectedCountryCode])
|
||||
{
|
||||
countryName = [dict valueForKey:@"country"];
|
||||
break;
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
// there is no country code selection
|
||||
if (!isSelectingCountryCode)
|
||||
{
|
||||
MXKTableViewCellWithLabelAndSubLabel *countryCell = [tableView dequeueReusableCellWithIdentifier:[MXKTableViewCellWithLabelAndSubLabel defaultReuseIdentifier]];
|
||||
if (!countryCell)
|
||||
{
|
||||
countryCell = [[MXKTableViewCellWithLabelAndSubLabel alloc] init];
|
||||
}
|
||||
|
||||
countryCell.mxkLabel.text = NSLocalizedStringFromTable(@"settings_country_select", @"MatrixConsole", nil);
|
||||
countryCell.mxkSublabel.text = countryName;
|
||||
countryCell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
|
||||
cell = countryCell;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// there is a selection in progress
|
||||
MXKTableViewCellWithPicker *pickerCell = [tableView dequeueReusableCellWithIdentifier:[MXKTableViewCellWithPicker defaultReuseIdentifier]];
|
||||
if (!pickerCell)
|
||||
{
|
||||
pickerCell = [[MXKTableViewCellWithPicker alloc] init];
|
||||
}
|
||||
|
||||
// display a picker
|
||||
pickerCell.mxkPickerView.delegate = self;
|
||||
pickerCell.mxkPickerView.dataSource = self;
|
||||
|
||||
if (countryName.length > 0)
|
||||
{
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[pickerCell.mxkPickerView selectRow:index inComponent:0 animated:NO];
|
||||
});
|
||||
}
|
||||
|
||||
cell = pickerCell;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else if (indexPath.section == SETTINGS_SECTION_ROOMS_INDEX)
|
||||
{
|
||||
if (indexPath.row == SETTINGS_SECTION_ROOMS_CLEAR_CACHE_INDEX)
|
||||
{
|
||||
MXKTableViewCellWithButton *clearCacheBtnCell = [tableView dequeueReusableCellWithIdentifier:[MXKTableViewCellWithButton defaultReuseIdentifier]];
|
||||
if (!clearCacheBtnCell)
|
||||
{
|
||||
clearCacheBtnCell = [[MXKTableViewCellWithButton alloc] init];
|
||||
}
|
||||
|
||||
NSString *btnTitle = [NSString stringWithFormat:@"%@ (%@)", NSLocalizedStringFromTable(@"settings_clear_cache", @"MatrixConsole", nil), [NSByteCountFormatter stringFromByteCount:self.cachesSize countStyle:NSByteCountFormatterCountStyleFile]];
|
||||
[clearCacheBtnCell.mxkButton setTitle:btnTitle forState:UIControlStateNormal];
|
||||
[clearCacheBtnCell.mxkButton setTitle:btnTitle forState:UIControlStateHighlighted];
|
||||
|
||||
clearCacheButton = clearCacheBtnCell.mxkButton;
|
||||
|
||||
[clearCacheButton removeTarget:self action:nil forControlEvents:UIControlEventTouchUpInside];
|
||||
[clearCacheButton addTarget:self action:@selector(onButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
|
||||
|
||||
cell = clearCacheBtnCell;
|
||||
}
|
||||
else if (indexPath.row == SETTINGS_SECTION_ROOMS_SET_CACHE_SIZE_INDEX)
|
||||
{
|
||||
maxCacheSizeCell = [tableView dequeueReusableCellWithIdentifier:[MXKTableViewCellWithLabelAndSlider defaultReuseIdentifier]];
|
||||
if (!maxCacheSizeCell)
|
||||
{
|
||||
maxCacheSizeCell = [[MXKTableViewCellWithLabelAndSlider alloc] init];
|
||||
}
|
||||
|
||||
maxCacheSizeCell.mxkSlider.minimumValue = 0;
|
||||
maxCacheSizeCell.mxkSlider.maximumValue = self.maxAllowedCachesSize;
|
||||
maxCacheSizeCell.mxkSlider.value = self.currentMaxCachesSize;
|
||||
|
||||
[self onSliderValueChange:maxCacheSizeCell.mxkSlider];
|
||||
|
||||
[maxCacheSizeCell.mxkSlider addTarget:self action:@selector(onSliderValueChange:) forControlEvents:UIControlEventValueChanged];
|
||||
cell = maxCacheSizeCell;
|
||||
}
|
||||
else
|
||||
{
|
||||
MXKTableViewCellWithLabelAndSwitch *roomsSettingCell = [tableView dequeueReusableCellWithIdentifier:[MXKTableViewCellWithLabelAndSwitch defaultReuseIdentifier]];
|
||||
if (!roomsSettingCell)
|
||||
{
|
||||
roomsSettingCell = [[MXKTableViewCellWithLabelAndSwitch alloc] init];
|
||||
}
|
||||
|
||||
[roomsSettingCell.mxkSwitch addTarget:self action:@selector(onButtonPressed:) forControlEvents:UIControlEventValueChanged];
|
||||
|
||||
if (indexPath.row == SETTINGS_SECTION_ROOMS_DISPLAY_ALL_EVENTS_INDEX)
|
||||
{
|
||||
roomsSettingCell.mxkLabel.text = NSLocalizedStringFromTable(@"settings_display_all_events", @"MatrixConsole", nil);
|
||||
roomsSettingCell.mxkSwitch.on = [_settings showAllEventsInRoomHistory];
|
||||
allEventsSwitch = roomsSettingCell.mxkSwitch;
|
||||
}
|
||||
else if (indexPath.row == SETTINGS_SECTION_ROOMS_SHOW_REDACTIONS_INDEX)
|
||||
{
|
||||
roomsSettingCell.mxkLabel.text = NSLocalizedStringFromTable(@"settings_show_redactions", @"MatrixConsole", nil);
|
||||
roomsSettingCell.mxkSwitch.on = [_settings showRedactionsInRoomHistory];
|
||||
redactionsSwitch = roomsSettingCell.mxkSwitch;
|
||||
}
|
||||
else if (indexPath.row == SETTINGS_SECTION_ROOMS_SHOW_UNSUPPORTED_EVENTS_INDEX)
|
||||
{
|
||||
roomsSettingCell.mxkLabel.text = NSLocalizedStringFromTable(@"settings_show_unsupported_events", @"MatrixConsole", nil);
|
||||
roomsSettingCell.mxkSwitch.on = [_settings showUnsupportedEventsInRoomHistory];
|
||||
unsupportedEventsSwitch = roomsSettingCell.mxkSwitch;
|
||||
}
|
||||
else if (indexPath.row == SETTINGS_SECTION_ROOMS_SORT_MEMBERS_INDEX)
|
||||
{
|
||||
roomsSettingCell.mxkLabel.text = NSLocalizedStringFromTable(@"settings_sort_by_last_seen", @"MatrixConsole", nil);
|
||||
roomsSettingCell.mxkSwitch.on = [_settings sortRoomMembersUsingLastSeenTime];
|
||||
sortMembersSwitch = roomsSettingCell.mxkSwitch;
|
||||
}
|
||||
else if (indexPath.row == SETTINGS_SECTION_ROOMS_DISPLAY_LEFT_MEMBERS_INDEX)
|
||||
{
|
||||
roomsSettingCell.mxkLabel.text = NSLocalizedStringFromTable(@"settings_display_left_members", @"MatrixConsole", nil);
|
||||
roomsSettingCell.mxkSwitch.on = [_settings showLeftMembersInRoomMemberList];
|
||||
displayLeftMembersSwitch = roomsSettingCell.mxkSwitch;
|
||||
}
|
||||
|
||||
cell = roomsSettingCell;
|
||||
}
|
||||
}
|
||||
else if (indexPath.section == SETTINGS_SECTION_CONFIGURATION_INDEX)
|
||||
{
|
||||
MXKTableViewCellWithTextView *configurationCell = [tableView dequeueReusableCellWithIdentifier:[MXKTableViewCellWithTextView defaultReuseIdentifier]];
|
||||
if (!configurationCell)
|
||||
{
|
||||
configurationCell = [[MXKTableViewCellWithTextView alloc] init];
|
||||
}
|
||||
|
||||
NSString* appVersion = [AppDelegate theDelegate].appVersion;
|
||||
NSString* build = [AppDelegate theDelegate].build;
|
||||
if (build.length)
|
||||
{
|
||||
build = [NSString stringWithFormat:NSLocalizedStringFromTable(@"settings_config_build_number", @"MatrixConsole", nil), build];
|
||||
}
|
||||
NSString *configurationFormatText = [NSString stringWithFormat:@"%@\n%@\n%@\n%@", NSLocalizedStringFromTable(@"settings_config_ios_console_version", @"MatrixConsole", nil), NSLocalizedStringFromTable(@"settings_config_ios_kit_version", @"MatrixConsole", nil), NSLocalizedStringFromTable(@"settings_config_ios_sdk_version", @"MatrixConsole", nil), @"%@"];
|
||||
configurationCell.mxkTextView.text = [NSString stringWithFormat:configurationFormatText, appVersion, MatrixKitVersion, MatrixSDKVersion, build];
|
||||
cell = configurationCell;
|
||||
}
|
||||
else if (indexPath.section == SETTINGS_SECTION_COMMANDS_INDEX)
|
||||
{
|
||||
MXKTableViewCellWithTextView *commandsCell = [tableView dequeueReusableCellWithIdentifier:[MXKTableViewCellWithTextView defaultReuseIdentifier]];
|
||||
if (!commandsCell)
|
||||
{
|
||||
commandsCell = [[MXKTableViewCellWithTextView alloc] init];
|
||||
}
|
||||
|
||||
commandsCell.mxkTextView.text = NSLocalizedStringFromTable(@"settings_command_commands", @"MatrixConsole", nil);
|
||||
cell = commandsCell;
|
||||
}
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
#pragma mark - UITableView delegate
|
||||
|
||||
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
if (indexPath.section == SETTINGS_SECTION_ACCOUNTS_INDEX)
|
||||
{
|
||||
return 50;
|
||||
}
|
||||
else if (indexPath.section == SETTINGS_SECTION_CONTACTS_INDEX)
|
||||
{
|
||||
|
||||
if ((indexPath.row == countryCodeRowIndex) && isSelectingCountryCode)
|
||||
{
|
||||
|
||||
return 164;
|
||||
}
|
||||
}
|
||||
else if (indexPath.section == SETTINGS_SECTION_ROOMS_INDEX)
|
||||
{
|
||||
if (indexPath.row == SETTINGS_SECTION_ROOMS_SET_CACHE_SIZE_INDEX)
|
||||
{
|
||||
return 88;
|
||||
}
|
||||
}
|
||||
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];
|
||||
NSString* appVersion = [AppDelegate theDelegate].appVersion;
|
||||
NSString* build = [AppDelegate theDelegate].build;
|
||||
if (build.length)
|
||||
{
|
||||
build = [NSString stringWithFormat:NSLocalizedStringFromTable(@"settings_config_build_number", @"MatrixConsole", nil), build];
|
||||
}
|
||||
NSString *configurationFormatText = [NSString stringWithFormat:@"%@\n%@\n%@\n%@", NSLocalizedStringFromTable(@"settings_config_ios_console_version", @"MatrixConsole", nil), NSLocalizedStringFromTable(@"settings_config_ios_kit_version", @"MatrixConsole", nil), NSLocalizedStringFromTable(@"settings_config_ios_sdk_version", @"MatrixConsole", nil), @"%@"];
|
||||
textView.text = [NSString stringWithFormat:configurationFormatText, appVersion, MatrixKitVersion, MatrixSDKVersion, build];
|
||||
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 = NSLocalizedStringFromTable(@"settings_command_commands", @"MatrixConsole", nil);
|
||||
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
|
||||
{
|
||||
UIView *sectionHeader = [[UIView alloc] initWithFrame:[tableView rectForHeaderInSection:section]];
|
||||
sectionHeader.backgroundColor = [UIColor colorWithRed:0.9 green:0.9 blue:0.9 alpha:1.0];
|
||||
UILabel *sectionLabel = [[UILabel alloc] initWithFrame:CGRectMake(5, 5, sectionHeader.frame.size.width - 10, sectionHeader.frame.size.height - 10)];
|
||||
sectionLabel.font = [UIFont boldSystemFontOfSize:16];
|
||||
sectionLabel.backgroundColor = [UIColor clearColor];
|
||||
[sectionHeader addSubview:sectionLabel];
|
||||
|
||||
if (section == SETTINGS_SECTION_ACCOUNTS_INDEX)
|
||||
{
|
||||
sectionLabel.text = NSLocalizedStringFromTable(@"accounts", @"MatrixConsole", nil);
|
||||
|
||||
UIButton *addAccount = [UIButton buttonWithType:UIButtonTypeContactAdd];
|
||||
[addAccount addTarget:self action:@selector(addAccount:) forControlEvents:UIControlEventTouchUpInside];
|
||||
|
||||
CGRect frame = addAccount.frame;
|
||||
frame.origin.x = sectionHeader.frame.size.width - frame.size.width - 8;
|
||||
frame.origin.y = (sectionHeader.frame.size.height - frame.size.height) / 2;
|
||||
addAccount.frame = frame;
|
||||
|
||||
[sectionHeader addSubview:addAccount];
|
||||
addAccount.autoresizingMask = (UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin);
|
||||
|
||||
sectionHeader.userInteractionEnabled = YES;
|
||||
}
|
||||
else if (section == SETTINGS_SECTION_CONTACTS_INDEX)
|
||||
{
|
||||
sectionLabel.text = NSLocalizedStringFromTable(@"contacts", @"MatrixConsole", nil);
|
||||
}
|
||||
else if (section == SETTINGS_SECTION_ROOMS_INDEX)
|
||||
{
|
||||
sectionLabel.text = NSLocalizedStringFromTable(@"settings_title_rooms", @"MatrixConsole", nil);
|
||||
}
|
||||
else if (section == SETTINGS_SECTION_CONFIGURATION_INDEX)
|
||||
{
|
||||
sectionLabel.text = NSLocalizedStringFromTable(@"settings_title_config", @"MatrixConsole", nil);
|
||||
}
|
||||
else if (section == SETTINGS_SECTION_COMMANDS_INDEX)
|
||||
{
|
||||
sectionLabel.text = NSLocalizedStringFromTable(@"settings_title_commands", @"MatrixConsole", nil);
|
||||
}
|
||||
else
|
||||
{
|
||||
sectionHeader = nil;
|
||||
}
|
||||
return sectionHeader;
|
||||
}
|
||||
|
||||
- (void)tableView:(UITableView *)aTableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
if (self.tableView == aTableView)
|
||||
{
|
||||
if (indexPath.section == SETTINGS_SECTION_ACCOUNTS_INDEX)
|
||||
{
|
||||
NSArray *accounts = [[MXKAccountManager sharedManager] accounts];
|
||||
if (indexPath.row < accounts.count)
|
||||
{
|
||||
selectedAccount = [accounts objectAtIndex:indexPath.row];
|
||||
|
||||
[self performSegueWithIdentifier:@"showAccountDetails" sender:self];
|
||||
}
|
||||
}
|
||||
else if (indexPath.section == SETTINGS_SECTION_CONTACTS_INDEX)
|
||||
{
|
||||
if (indexPath.row == countryCodeRowIndex)
|
||||
{
|
||||
isSelectingCountryCode = YES;
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self.tableView reloadData];
|
||||
});
|
||||
}
|
||||
}
|
||||
[aTableView deselectRowAtIndexPath:indexPath animated:YES];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - UIPickerViewDataSource
|
||||
|
||||
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
|
||||
{
|
||||
return [countryCodes count];
|
||||
}
|
||||
|
||||
#pragma mark - UIPickerViewDelegate
|
||||
|
||||
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
|
||||
{
|
||||
return [[countryCodes objectAtIndex:row] valueForKey:@"country"];
|
||||
}
|
||||
|
||||
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
|
||||
{
|
||||
// sanity check
|
||||
if ((row >= 0) && (row < countryCodes.count))
|
||||
{
|
||||
NSDictionary* dict = [countryCodes objectAtIndex:row];
|
||||
selectedCountryCode = [dict valueForKey:@"id"];
|
||||
}
|
||||
|
||||
isSelectingCountryCode = NO;
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self.tableView reloadData];
|
||||
});
|
||||
}
|
||||
|
||||
#pragma mark - Cache handling
|
||||
|
||||
// return the MX cache size in bytes
|
||||
- (NSUInteger)MXCacheSize
|
||||
{
|
||||
NSUInteger cacheSize = 0;
|
||||
|
||||
NSArray *mxSessions = self.mxSessions;
|
||||
for (MXSession *mxSession in mxSessions)
|
||||
{
|
||||
if (mxSession.store && [mxSession.store isKindOfClass:[MXFileStore class]])
|
||||
{
|
||||
MXFileStore *fileStore = (MXFileStore*)mxSession.store;
|
||||
cacheSize += fileStore.diskUsage;
|
||||
}
|
||||
}
|
||||
|
||||
return cacheSize;
|
||||
}
|
||||
|
||||
// return the sum of the caches (MX cache + media cache ...) in bytes
|
||||
- (NSUInteger)cachesSize
|
||||
{
|
||||
return self.MXCacheSize + [MXKMediaManager cacheSize];
|
||||
}
|
||||
|
||||
// defines the min allow cache size in bytes
|
||||
- (NSUInteger)minCachesSize
|
||||
{
|
||||
// add a 50MB margin to avoid cache file deletion
|
||||
return self.MXCacheSize + [MXKMediaManager minCacheSize] + 50 * 1024 * 1024;
|
||||
}
|
||||
|
||||
// defines the current max caches size in bytes
|
||||
- (NSUInteger)currentMaxCachesSize
|
||||
{
|
||||
return self.MXCacheSize + [MXKMediaManager currentMaxCacheSize];
|
||||
}
|
||||
|
||||
- (void)setCurrentMaxCachesSize:(NSUInteger)maxCachesSize
|
||||
{
|
||||
[MXKMediaManager setCurrentMaxCacheSize:maxCachesSize - self.MXCacheSize];
|
||||
}
|
||||
|
||||
// defines the max allowed caches size in bytes
|
||||
- (NSUInteger) maxAllowedCachesSize
|
||||
{
|
||||
return self.MXCacheSize + [MXKMediaManager maxAllowedCacheSize];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
Copyright 2015 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 <Foundation/Foundation.h>
|
||||
|
||||
/*
|
||||
This file exists only to force Xcode to use the GNU c++ standard library (libstdc++).
|
||||
Even if the project settings indicate they want to use libstdc++, if there is no .mm file, Xcode
|
||||
continues to use its c++ lib. That prevents the app from linking if it includes some .hh files.
|
||||
|
||||
@see: http://stackoverflow.com/a/19250215/3936576
|
||||
|
||||
*/
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
Copyright 2015 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"
|
||||
|
||||
#import <MXLogger.h>
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
@autoreleasepool {
|
||||
|
||||
// Redirect NSLogs to files only if we are not debugging
|
||||
if (!isatty(STDERR_FILENO)) {
|
||||
[MXLogger redirectNSLogToFiles:YES];
|
||||
}
|
||||
// Catch and log crashes
|
||||
[MXLogger logCrashes:YES];
|
||||
|
||||
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user