mirror of
https://github.com/vector-im/element-ios.git
synced 2024-09-29 07:42:40 +00:00
Update Console by using MXKAuthenticationViewController and MXKAccount classes.
This commit is contained in:
parent
b3f3b785f0
commit
216f7d1cf9
17 changed files with 274 additions and 2003 deletions
|
@ -8,7 +8,6 @@
|
|||
|
||||
/* Begin PBXBuildFile section */
|
||||
3198D9E11A68338B00556695 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 3198D9E31A68338B00556695 /* Localizable.strings */; };
|
||||
32501A9B1A9B978400C5938F /* MXCRegistrationWebView.m in Sources */ = {isa = PBXBuildFile; fileRef = 32501A9A1A9B978400C5938F /* MXCRegistrationWebView.m */; };
|
||||
710CC3BF1A6E9F14006EE973 /* matrixUser.png in Resources */ = {isa = PBXBuildFile; fileRef = 710CC3BE1A6E9F14006EE973 /* matrixUser.png */; };
|
||||
710CC3C21A70F28F006EE973 /* MXCContactField.m in Sources */ = {isa = PBXBuildFile; fileRef = 710CC3C11A70F28F006EE973 /* MXCContactField.m */; };
|
||||
71193D241A6D64F900E59A9E /* AddressBook.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 71193D231A6D64F900E59A9E /* AddressBook.framework */; };
|
||||
|
@ -56,7 +55,6 @@
|
|||
F08DB7811A9B7C9300B73403 /* PublicRoomTableCell.m in Sources */ = {isa = PBXBuildFile; fileRef = F08DB7801A9B7C9300B73403 /* PublicRoomTableCell.m */; };
|
||||
F08DCBDB1A093BFA008C65B6 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F08DCBDA1A093BFA008C65B6 /* MobileCoreServices.framework */; };
|
||||
F08E67961A77965A00AABD4C /* MXC3PID.m in Sources */ = {isa = PBXBuildFile; fileRef = F08E67931A77965A00AABD4C /* MXC3PID.m */; };
|
||||
F0AC79331A8394510056D042 /* AuthInputsView.m in Sources */ = {isa = PBXBuildFile; fileRef = F0AC79321A8394510056D042 /* AuthInputsView.m */; };
|
||||
F0ADEFFB1AD7D2B3008A4F21 /* RoomMembersViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = F0ADEFFA1AD7D2B3008A4F21 /* RoomMembersViewController.m */; };
|
||||
F0CEA5AE19E6895E00E47915 /* logoHighRes.png in Resources */ = {isa = PBXBuildFile; fileRef = F0CEA5AC19E6895E00E47915 /* logoHighRes.png */; };
|
||||
F0CEA5AF19E6895E00E47915 /* tab_recents.png in Resources */ = {isa = PBXBuildFile; fileRef = F0CEA5AD19E6895E00E47915 /* tab_recents.png */; };
|
||||
|
@ -83,8 +81,6 @@
|
|||
/* Begin PBXFileReference section */
|
||||
13057A57E74FD5504196F47F /* Pods-matrixConsole.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-matrixConsole.release.xcconfig"; path = "Pods/Target Support Files/Pods-matrixConsole/Pods-matrixConsole.release.xcconfig"; sourceTree = "<group>"; };
|
||||
3198D9E21A68338B00556695 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
32501A991A9B978400C5938F /* MXCRegistrationWebView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MXCRegistrationWebView.h; sourceTree = "<group>"; };
|
||||
32501A9A1A9B978400C5938F /* MXCRegistrationWebView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MXCRegistrationWebView.m; sourceTree = "<group>"; };
|
||||
710CC3BE1A6E9F14006EE973 /* matrixUser.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = matrixUser.png; sourceTree = "<group>"; };
|
||||
710CC3C01A70F28F006EE973 /* MXCContactField.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MXCContactField.h; sourceTree = "<group>"; };
|
||||
710CC3C11A70F28F006EE973 /* MXCContactField.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MXCContactField.m; sourceTree = "<group>"; };
|
||||
|
@ -162,8 +158,6 @@
|
|||
F08DCBDA1A093BFA008C65B6 /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = System/Library/Frameworks/MobileCoreServices.framework; sourceTree = SDKROOT; };
|
||||
F08E67921A77965A00AABD4C /* MXC3PID.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MXC3PID.h; sourceTree = "<group>"; };
|
||||
F08E67931A77965A00AABD4C /* MXC3PID.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MXC3PID.m; sourceTree = "<group>"; };
|
||||
F0AC79311A8394510056D042 /* AuthInputsView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AuthInputsView.h; sourceTree = "<group>"; };
|
||||
F0AC79321A8394510056D042 /* AuthInputsView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AuthInputsView.m; sourceTree = "<group>"; };
|
||||
F0ADEFF91AD7D2B3008A4F21 /* RoomMembersViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RoomMembersViewController.h; sourceTree = "<group>"; };
|
||||
F0ADEFFA1AD7D2B3008A4F21 /* RoomMembersViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RoomMembersViewController.m; sourceTree = "<group>"; };
|
||||
F0CEA5AC19E6895E00E47915 /* logoHighRes.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = logoHighRes.png; sourceTree = "<group>"; };
|
||||
|
@ -302,14 +296,10 @@
|
|||
F03EF5FC19F1762000A0EE52 /* View */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F0AC79311A8394510056D042 /* AuthInputsView.h */,
|
||||
F0AC79321A8394510056D042 /* AuthInputsView.m */,
|
||||
7176294D1A77FED800927125 /* ContactDetailsTableCell.h */,
|
||||
7176294E1A77FED800927125 /* ContactDetailsTableCell.m */,
|
||||
71193D2A1A6E433900E59A9E /* ContactTableCell.h */,
|
||||
71193D2B1A6E433900E59A9E /* ContactTableCell.m */,
|
||||
32501A991A9B978400C5938F /* MXCRegistrationWebView.h */,
|
||||
32501A9A1A9B978400C5938F /* MXCRegistrationWebView.m */,
|
||||
F08DB77F1A9B7C9300B73403 /* PublicRoomTableCell.h */,
|
||||
F08DB7801A9B7C9300B73403 /* PublicRoomTableCell.m */,
|
||||
F0E84D3E1A1F9AEC005F2E42 /* RecentsTableViewCell.h */,
|
||||
|
@ -570,7 +560,6 @@
|
|||
files = (
|
||||
7176294F1A77FED800927125 /* ContactDetailsTableCell.m in Sources */,
|
||||
F04A8AD81A3B3DF4008AC915 /* RoomTitleView.m in Sources */,
|
||||
32501A9B1A9B978400C5938F /* MXCRegistrationWebView.m in Sources */,
|
||||
F07A80DB19DD9DE700B621A1 /* AppDelegate.m in Sources */,
|
||||
F0ADEFFB1AD7D2B3008A4F21 /* RoomMembersViewController.m in Sources */,
|
||||
F08DB7811A9B7C9300B73403 /* PublicRoomTableCell.m in Sources */,
|
||||
|
@ -600,7 +589,6 @@
|
|||
F03EF5F719F171EB00A0EE52 /* AuthenticationViewController.m in Sources */,
|
||||
F0D3C30F1A01330F0000D49E /* SettingsTableViewCell.m in Sources */,
|
||||
71D2E4EC1A49814B000DE015 /* RoomMemberActionsCell.m in Sources */,
|
||||
F0AC79331A8394510056D042 /* AuthInputsView.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
|
|
@ -13,10 +13,10 @@
|
|||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
#import <MatrixKit/MatrixKit.h>
|
||||
|
||||
#import "APNSHandler.h"
|
||||
#import "AppDelegate.h"
|
||||
#import "MatrixHandler.h"
|
||||
|
||||
NSString *const kAPNSHandlerHasBeenUpdated = @"kAPNSHandlerHasBeenUpdated";
|
||||
|
||||
|
@ -91,7 +91,7 @@ static APNSHandler *sharedHandler = nil;
|
|||
|
||||
- (void)setIsActive:(BOOL)isActive {
|
||||
// Refuse to try & turn push on if we're not logged in, it's nonsensical.
|
||||
if (![MatrixHandler sharedHandler].accessToken) {
|
||||
if (![MXKAccountManager sharedManager].accounts.count) {
|
||||
NSLog(@"[APNSHandler] Not setting push token because we're not logged in");
|
||||
return;
|
||||
}
|
||||
|
@ -126,18 +126,23 @@ static APNSHandler *sharedHandler = nil;
|
|||
}
|
||||
|
||||
NSObject *kind = isActive ? @"http" : [NSNull null];
|
||||
|
||||
MXRestClient *restCli = [MatrixHandler sharedHandler].mxRestClient;
|
||||
[restCli setPusherWithPushkey:b64Token kind:kind appId:appId appDisplayName:@"Matrix Console iOS" deviceDisplayName:[[UIDevice currentDevice] name] profileTag:profileTag lang:deviceLang data:pushData success:^{
|
||||
[[NSUserDefaults standardUserDefaults] setBool:transientActivity forKey:@"apnsIsActive"];
|
||||
[[NSUserDefaults standardUserDefaults] synchronize];
|
||||
|
||||
// TODO GFO Handle correctly multi-session here
|
||||
NSArray *mxAccounts = [MXKAccountManager sharedManager].accounts;
|
||||
for (MXKAccount *account in mxAccounts) {
|
||||
MXRestClient *restCli = account.mxRestClient;
|
||||
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:kAPNSHandlerHasBeenUpdated object:nil];
|
||||
} failure:^(NSError *error) {
|
||||
NSLog(@"[APNSHandler] Failed to send APNS token! (%@)", error);
|
||||
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:kAPNSHandlerHasBeenUpdated object:nil];
|
||||
}];
|
||||
[restCli setPusherWithPushkey:b64Token kind:kind appId:appId appDisplayName:@"Matrix Console iOS" deviceDisplayName:[[UIDevice currentDevice] name] profileTag:profileTag lang:deviceLang data:pushData success:^{
|
||||
[[NSUserDefaults standardUserDefaults] setBool:transientActivity forKey:@"apnsIsActive"];
|
||||
[[NSUserDefaults standardUserDefaults] synchronize];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:kAPNSHandlerHasBeenUpdated object:nil];
|
||||
} failure:^(NSError *error) {
|
||||
NSLog(@"[APNSHandler] Failed to send APNS token for %@! (%@)", account.mxCredentials.userId, error);
|
||||
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:kAPNSHandlerHasBeenUpdated object:nil];
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -21,35 +21,14 @@
|
|||
@property (strong, nonatomic) MXRestClient *mxRestClient;
|
||||
@property (strong, nonatomic) MXSession *mxSession;
|
||||
|
||||
@property (strong, nonatomic) NSString *homeServerURL;
|
||||
@property (strong, nonatomic) NSString *homeServer;
|
||||
@property (strong, nonatomic) NSString *userLogin;
|
||||
@property (strong, nonatomic) NSString *userId;
|
||||
@property (strong, nonatomic, readonly) NSString *localPartFromUserId;
|
||||
@property (strong, nonatomic) NSString *accessToken;
|
||||
@property (strong, nonatomic) NSString *identityServerURL;
|
||||
|
||||
// Matrix user's settings
|
||||
@property (nonatomic) MXPresence userPresence;
|
||||
|
||||
+ (MatrixHandler *)sharedHandler;
|
||||
|
||||
- (void)pauseInBackgroundTask;
|
||||
- (void)resume;
|
||||
- (void)logout;
|
||||
|
||||
// Flush and restore Matrix data
|
||||
- (void)reload:(BOOL)clearCache;
|
||||
|
||||
// Searches if a private OneToOne room has been started with this user
|
||||
// Returns the room ID (nil if not found)
|
||||
- (NSString*)privateOneToOneRoomIdWithUserId:(NSString*)userId;
|
||||
// Reopens an existing private OneToOne room with this userId or creates a new one (if it doesn't exist)
|
||||
- (void)startPrivateOneToOneRoomWithUserId:(NSString*)userId;
|
||||
|
||||
// Enables inApp notifications for a dedicated room if they were disabled
|
||||
- (void)restoreInAppNotificationsForRoomId:(NSString*)roomID;
|
||||
|
||||
// user power level in a dedicated room
|
||||
- (CGFloat)getPowerLevel:(MXRoomMember *)roomMember inRoom:(MXRoom *)room;
|
||||
|
||||
|
|
|
@ -17,44 +17,8 @@
|
|||
#import "MatrixHandler.h"
|
||||
#import "AppDelegate.h"
|
||||
|
||||
#import "MXFileStore.h"
|
||||
#import "MXTools.h"
|
||||
|
||||
#import "AFNetworkReachabilityManager.h"
|
||||
|
||||
#import <AudioToolbox/AudioToolbox.h>
|
||||
|
||||
static MatrixHandler *sharedHandler = nil;
|
||||
|
||||
@interface MatrixHandler () {
|
||||
// We will notify user only once on session failure
|
||||
BOOL notifyOpenSessionFailure;
|
||||
NSTimer* initialServerSyncTimer;
|
||||
|
||||
// Handle user's settings change
|
||||
id userUpdateListener;
|
||||
// Handle events notification
|
||||
id notificationCenterListener;
|
||||
// Reachability observer
|
||||
id reachabilityObserver;
|
||||
|
||||
// Used for logging application start up
|
||||
NSDate *openSessionStartDate;
|
||||
|
||||
MXKEventFormatter *eventFormatter;
|
||||
}
|
||||
|
||||
@property (strong, nonatomic) MXFileStore *mxFileStore;
|
||||
|
||||
@property (strong, nonatomic) MXKAlert *mxNotification;
|
||||
@property (nonatomic) UIBackgroundTaskIdentifier bgTask;
|
||||
|
||||
// When the user cancels an inApp notification
|
||||
// assume that any messagge room will be ignored
|
||||
// until the next launch / debackground
|
||||
@property (nonatomic,readwrite) NSMutableArray* unnotifiedRooms;
|
||||
@end
|
||||
|
||||
@implementation MatrixHandler
|
||||
|
||||
+ (MatrixHandler *)sharedHandler {
|
||||
|
@ -67,488 +31,20 @@ static MatrixHandler *sharedHandler = nil;
|
|||
return sharedHandler;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
-(MatrixHandler *)init {
|
||||
if (self = [super init]) {
|
||||
_userPresence = MXPresenceUnknown;
|
||||
notifyOpenSessionFailure = YES;
|
||||
|
||||
// Read potential homeserver url in shared defaults object
|
||||
if (self.homeServerURL) {
|
||||
self.mxRestClient = [[MXRestClient alloc] initWithHomeServer:self.homeServerURL];
|
||||
if (self.identityServerURL) {
|
||||
[self.mxRestClient setIdentityServer:self.identityServerURL];
|
||||
}
|
||||
|
||||
if (self.accessToken) {
|
||||
[self openSession];
|
||||
}
|
||||
}
|
||||
|
||||
_unnotifiedRooms = [[NSMutableArray alloc] init];
|
||||
|
||||
[[MXKAppSettings standardAppSettings] addObserver:self forKeyPath:@"enableInAppNotifications" options:0 context:nil];
|
||||
[[MXKAppSettings standardAppSettings] addObserver:self forKeyPath:@"showAllEventsInRoomHistory" options:0 context:nil];
|
||||
}
|
||||
return self;
|
||||
- (MXSession*)mxSession {
|
||||
// Only the first account is presently used
|
||||
MXKAccount *account = [[MXKAccountManager sharedManager].accounts firstObject];
|
||||
return account.mxSession;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[[MXKAppSettings standardAppSettings] removeObserver:self forKeyPath:@"enableInAppNotifications"];
|
||||
[[MXKAppSettings standardAppSettings] removeObserver:self forKeyPath:@"showAllEventsInRoomHistory"];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:reachabilityObserver];
|
||||
reachabilityObserver = nil;
|
||||
|
||||
[initialServerSyncTimer invalidate];
|
||||
initialServerSyncTimer = nil;
|
||||
|
||||
_unnotifiedRooms = nil;
|
||||
|
||||
[self closeSession];
|
||||
self.mxSession = nil;
|
||||
|
||||
if (self.mxNotification) {
|
||||
[self.mxNotification dismiss:NO];
|
||||
self.mxNotification = nil;
|
||||
}
|
||||
- (MXRestClient*)mxRestClient {
|
||||
// Only the first account is presently used
|
||||
MXKAccount *account = [[MXKAccountManager sharedManager].accounts firstObject];
|
||||
return account.mxRestClient;
|
||||
}
|
||||
|
||||
- (void)openSession {
|
||||
MXCredentials *credentials = [[MXCredentials alloc] initWithHomeServer:self.homeServerURL
|
||||
userId:self.userId
|
||||
accessToken:self.accessToken];
|
||||
|
||||
openSessionStartDate = [NSDate date];
|
||||
self.mxRestClient = [[MXRestClient alloc] initWithCredentials:credentials];
|
||||
if (self.mxRestClient) {
|
||||
// Set identity server (if any)
|
||||
if (self.identityServerURL) {
|
||||
[self.mxRestClient setIdentityServer:self.identityServerURL];
|
||||
}
|
||||
|
||||
// Use MXFileStore as MXStore to permanently store events
|
||||
_mxFileStore = [[MXFileStore alloc] init];
|
||||
|
||||
self.mxSession = [[MXSession alloc] initWithMatrixRestClient:self.mxRestClient];
|
||||
|
||||
// Build MXEvent -> NSString formatter
|
||||
eventFormatter = [[MXKEventFormatter alloc] initWithMatrixSession:self.mxSession];
|
||||
eventFormatter.isForSubtitle = YES;
|
||||
|
||||
__weak typeof(self) weakSelf = self;
|
||||
[self.mxSession setStore:_mxFileStore success:^{
|
||||
// Complete session registration by launching live stream
|
||||
typeof(self) self = weakSelf;
|
||||
[self launchInitialServerSync];
|
||||
} failure:^(NSError *error) {
|
||||
// This cannot happen. Loading of MXFileStore cannot fail.
|
||||
typeof(self) self = weakSelf;
|
||||
self.mxSession = nil;
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)launchInitialServerSync {
|
||||
// Complete the session registration when store data is ready.
|
||||
|
||||
// Cancel potential reachability observer and pending action
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:reachabilityObserver];
|
||||
reachabilityObserver = nil;
|
||||
[initialServerSyncTimer invalidate];
|
||||
initialServerSyncTimer = nil;
|
||||
|
||||
// Sanity check
|
||||
if (self.mxSession.state != MXSessionStateStoreDataReady) {
|
||||
NSLog(@"[MatrixHandler] Initial server sync is applicable only when store data is ready to complete session initialisation");
|
||||
return;
|
||||
}
|
||||
|
||||
// Launch mxSession
|
||||
[self.mxSession start:^{
|
||||
NSLog(@"[MatrixHandler] The app is ready. Matrix SDK session has been started in %0.fms.", [[NSDate date] timeIntervalSinceDate:openSessionStartDate] * 1000);
|
||||
[self setUserPresence:MXPresenceOnline andStatusMessage:nil completion:nil];
|
||||
|
||||
// Register listener to update user's information
|
||||
userUpdateListener = [self.mxSession.myUser listenToUserUpdate:^(MXEvent *event) {
|
||||
// Consider only events related to user's presence
|
||||
if (event.eventType == MXEventTypePresence) {
|
||||
MXPresence presence = [MXTools presence:event.content[@"presence"]];
|
||||
if (self.userPresence != presence) {
|
||||
// Handle user presence on multiple devices (keep the more pertinent)
|
||||
if (self.userPresence == MXPresenceOnline) {
|
||||
if (presence == MXPresenceUnavailable || presence == MXPresenceOffline) {
|
||||
// Force the local presence to overwrite the user presence on server side
|
||||
[self setUserPresence:_userPresence andStatusMessage:nil completion:nil];
|
||||
return;
|
||||
}
|
||||
} else if (self.userPresence == MXPresenceUnavailable) {
|
||||
if (presence == MXPresenceOffline) {
|
||||
// Force the local presence to overwrite the user presence on server side
|
||||
[self setUserPresence:_userPresence andStatusMessage:nil completion:nil];
|
||||
return;
|
||||
}
|
||||
}
|
||||
self.userPresence = presence;
|
||||
}
|
||||
}
|
||||
}];
|
||||
|
||||
// Check whether the app user wants notifications on new events
|
||||
if ([[MXKAppSettings standardAppSettings] enableInAppNotifications]) {
|
||||
[self enableInAppNotifications:YES];
|
||||
}
|
||||
} failure:^(NSError *error) {
|
||||
NSLog(@"[MatrixHandler] Initial Sync failed: %@", error);
|
||||
if (notifyOpenSessionFailure) {
|
||||
//Alert user only once
|
||||
notifyOpenSessionFailure = NO;
|
||||
[[AppDelegate theDelegate] showErrorAsAlert:error];
|
||||
}
|
||||
|
||||
// Check network reachability
|
||||
if ([error.domain isEqualToString:NSURLErrorDomain] && error.code == NSURLErrorNotConnectedToInternet) {
|
||||
// Add observer to launch a new attempt according to reachability.
|
||||
reachabilityObserver = [[NSNotificationCenter defaultCenter] addObserverForName:AFNetworkingReachabilityDidChangeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
|
||||
NSNumber *statusItem = note.userInfo[AFNetworkingReachabilityNotificationStatusItem];
|
||||
if (statusItem) {
|
||||
AFNetworkReachabilityStatus reachabilityStatus = statusItem.integerValue;
|
||||
if (reachabilityStatus == AFNetworkReachabilityStatusReachableViaWiFi || reachabilityStatus == AFNetworkReachabilityStatusReachableViaWWAN) {
|
||||
// New attempt
|
||||
[self launchInitialServerSync];
|
||||
}
|
||||
}
|
||||
}];
|
||||
} else {
|
||||
// Postpone a new attempt in 10 sec
|
||||
initialServerSyncTimer = [NSTimer scheduledTimerWithTimeInterval:10 target:self selector:@selector(launchInitialServerSync) userInfo:self repeats:NO];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)closeSession {
|
||||
|
||||
if (notificationCenterListener) {
|
||||
[self.mxSession.notificationCenter removeListener:notificationCenterListener];
|
||||
notificationCenterListener = nil;
|
||||
}
|
||||
if (userUpdateListener) {
|
||||
[self.mxSession.myUser removeListener:userUpdateListener];
|
||||
userUpdateListener = nil;
|
||||
}
|
||||
|
||||
[self.mxSession close];
|
||||
self.mxSession = nil;
|
||||
|
||||
[self.mxRestClient close];
|
||||
|
||||
if (self.homeServerURL) {
|
||||
self.mxRestClient = [[MXRestClient alloc] initWithHomeServer:self.homeServerURL];
|
||||
if (self.identityServerURL) {
|
||||
[self.mxRestClient setIdentityServer:self.identityServerURL];
|
||||
}
|
||||
} else {
|
||||
self.mxRestClient = nil;
|
||||
}
|
||||
|
||||
notifyOpenSessionFailure = YES;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (void)pauseInBackgroundTask {
|
||||
// Hide potential notification
|
||||
if (self.mxNotification) {
|
||||
[self.mxNotification dismiss:NO];
|
||||
self.mxNotification = nil;
|
||||
}
|
||||
|
||||
_unnotifiedRooms = [[NSMutableArray alloc] init];
|
||||
|
||||
if (self.mxSession && self.mxSession.state == MXSessionStateRunning) {
|
||||
_bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
|
||||
[[UIApplication sharedApplication] endBackgroundTask:_bgTask];
|
||||
_bgTask = UIBackgroundTaskInvalid;
|
||||
|
||||
NSLog(@"[MatrixHandler] pauseInBackgroundTask : %08lX expired", (unsigned long)_bgTask);
|
||||
}];
|
||||
|
||||
NSLog(@"[MatrixHandler] pauseInBackgroundTask : %08lX starts", (unsigned long)_bgTask);
|
||||
// Pause SDK
|
||||
[self.mxSession pause];
|
||||
// Update user presence
|
||||
__weak typeof(self) weakSelf = self;
|
||||
[self setUserPresence:MXPresenceUnavailable andStatusMessage:nil completion:^{
|
||||
NSLog(@"[MatrixHandler] pauseInBackgroundTask : %08lX ends", (unsigned long)weakSelf.bgTask);
|
||||
[[UIApplication sharedApplication] endBackgroundTask:weakSelf.bgTask];
|
||||
weakSelf.bgTask = UIBackgroundTaskInvalid;
|
||||
NSLog(@"[MatrixHandler] >>>>> background pause task finished");
|
||||
}];
|
||||
} else {
|
||||
// Cancel pending actions
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:reachabilityObserver];
|
||||
reachabilityObserver = nil;
|
||||
[initialServerSyncTimer invalidate];
|
||||
initialServerSyncTimer = nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)resume {
|
||||
if (self.mxSession) {
|
||||
if (self.mxSession.state == MXSessionStatePaused) {
|
||||
// Resume SDK and update user presence
|
||||
[self.mxSession resume:^{
|
||||
[self setUserPresence:MXPresenceOnline andStatusMessage:nil completion:nil];
|
||||
}];
|
||||
} else if (self.mxSession.state == MXSessionStateStoreDataReady) {
|
||||
// The session initialisation was uncompleted, we try to complete it here.
|
||||
[self launchInitialServerSync];
|
||||
}
|
||||
|
||||
if (_bgTask) {
|
||||
// Cancel background task
|
||||
[[UIApplication sharedApplication] endBackgroundTask:_bgTask];
|
||||
_bgTask = UIBackgroundTaskInvalid;
|
||||
NSLog(@"[MatrixHandler] pauseInBackgroundTask : %08lX cancelled", (unsigned long)_bgTask);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)logout {
|
||||
NSLog(@"[MatrixHandler] logout");
|
||||
|
||||
//[self setUserPresence:MXPresenceOffline andStatusMessage:nil completion:nil];
|
||||
|
||||
// Reset access token (mxSession is closed by setter)
|
||||
self.accessToken = nil;
|
||||
self.userId = nil;
|
||||
self.homeServer = nil;
|
||||
|
||||
_unnotifiedRooms = [[NSMutableArray alloc] init];
|
||||
// Keep userLogin, homeServerUrl
|
||||
}
|
||||
|
||||
- (void)reload:(BOOL)clearCache {
|
||||
if (self.mxSession) {
|
||||
[self closeSession];
|
||||
notifyOpenSessionFailure = NO;
|
||||
|
||||
// Force back to Recents list if room details is displayed (Room details are not available until the end of initial sync)
|
||||
[[AppDelegate theDelegate].masterTabBarController popRoomViewControllerAnimated:NO];
|
||||
|
||||
[[MXKRoomDataSourceManager sharedManagerForMatrixSession:self.mxSession] reset];
|
||||
|
||||
if (clearCache) {
|
||||
// clear the media cache
|
||||
[MXKMediaManager clearCache];
|
||||
|
||||
[_mxFileStore deleteAllData];
|
||||
}
|
||||
|
||||
if (self.accessToken) {
|
||||
[self openSession];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)enableInAppNotifications:(BOOL)isEnabled {
|
||||
if (isEnabled) {
|
||||
// Register on notification center
|
||||
notificationCenterListener = [self.mxSession.notificationCenter listenToNotifications:^(MXEvent *event, MXRoomState *roomState, MXPushRule *rule) {
|
||||
|
||||
// Apply first the event filter defined in the related room data source
|
||||
MXKRoomDataSourceManager *roomDataSourceManager = [MXKRoomDataSourceManager sharedManagerForMatrixSession:self.mxSession];
|
||||
MXKRoomDataSource *roomDataSource = [roomDataSourceManager roomDataSourceForRoom:event.roomId create:NO];
|
||||
if (!roomDataSource || [roomDataSource.eventsFilterForMessages indexOfObject:event.type] == NSNotFound) {
|
||||
// Ignore
|
||||
return;
|
||||
}
|
||||
|
||||
// Check conditions to display this notification
|
||||
if (![[AppDelegate theDelegate].masterTabBarController.visibleRoomId isEqualToString:event.roomId]
|
||||
&& ![[AppDelegate theDelegate].masterTabBarController isPresentingMediaPicker]
|
||||
&& ([self.unnotifiedRooms indexOfObject:event.roomId] == NSNotFound)) {
|
||||
|
||||
MXKEventFormatterError error;
|
||||
NSString* messageText = [eventFormatter stringFromEvent:event withRoomState:roomState error:&error];
|
||||
if (messageText.length && (error == MXKEventFormatterErrorNone)) {
|
||||
|
||||
// Removing existing notification (if any)
|
||||
if (self.mxNotification) {
|
||||
[self.mxNotification dismiss:NO];
|
||||
}
|
||||
|
||||
// Check whether tweak is required
|
||||
for (MXPushRuleAction *ruleAction in rule.actions) {
|
||||
if (ruleAction.actionType == MXPushRuleActionTypeSetTweak) {
|
||||
if ([[ruleAction.parameters valueForKey:@"set_tweak"] isEqualToString:@"sound"]) {
|
||||
// Play system sound (VoicemailReceived)
|
||||
AudioServicesPlaySystemSound (1002);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__weak typeof(self) weakSelf = self;
|
||||
self.mxNotification = [[MXKAlert alloc] initWithTitle:roomState.displayname
|
||||
message:messageText
|
||||
style:MXKAlertStyleAlert];
|
||||
self.mxNotification.cancelButtonIndex = [self.mxNotification addActionWithTitle:@"Cancel"
|
||||
style:MXKAlertActionStyleDefault
|
||||
handler:^(MXKAlert *alert) {
|
||||
weakSelf.mxNotification = nil;
|
||||
[weakSelf.unnotifiedRooms addObject:event.roomId];
|
||||
}];
|
||||
[self.mxNotification addActionWithTitle:@"View"
|
||||
style:MXKAlertActionStyleDefault
|
||||
handler:^(MXKAlert *alert) {
|
||||
weakSelf.mxNotification = nil;
|
||||
// Show the room
|
||||
[[AppDelegate theDelegate].masterTabBarController showRoom:event.roomId];
|
||||
}];
|
||||
|
||||
[self.mxNotification showInViewController:[[AppDelegate theDelegate].masterTabBarController selectedViewController]];
|
||||
}
|
||||
}
|
||||
}];
|
||||
} else {
|
||||
if (notificationCenterListener) {
|
||||
[self.mxSession.notificationCenter removeListener:notificationCenterListener];
|
||||
notificationCenterListener = nil;
|
||||
}
|
||||
if (self.mxNotification) {
|
||||
[self.mxNotification dismiss:NO];
|
||||
self.mxNotification = nil;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark User's profile
|
||||
|
||||
- (NSString *)homeServerURL {
|
||||
return [[NSUserDefaults standardUserDefaults] objectForKey:@"homeserverurl"];
|
||||
}
|
||||
|
||||
- (void)setHomeServerURL:(NSString *)inHomeServerURL {
|
||||
if (inHomeServerURL.length) {
|
||||
[[NSUserDefaults standardUserDefaults] setObject:inHomeServerURL forKey:@"homeserverurl"];
|
||||
self.mxRestClient = [[MXRestClient alloc] initWithHomeServer:inHomeServerURL];
|
||||
// Set identity server (if any)
|
||||
if (self.identityServerURL) {
|
||||
[self.mxRestClient setIdentityServer:self.identityServerURL];
|
||||
}
|
||||
} else {
|
||||
[[NSUserDefaults standardUserDefaults] removeObjectForKey:@"homeserverurl"];
|
||||
// Reinitialize matrix handler
|
||||
[self logout];
|
||||
}
|
||||
[[NSUserDefaults standardUserDefaults] synchronize];
|
||||
}
|
||||
|
||||
- (NSString *)homeServer {
|
||||
return [[NSUserDefaults standardUserDefaults] objectForKey:@"homeserver"];
|
||||
}
|
||||
|
||||
- (void)setHomeServer:(NSString *)inHomeserver {
|
||||
if (inHomeserver.length) {
|
||||
[[NSUserDefaults standardUserDefaults] setObject:inHomeserver forKey:@"homeserver"];
|
||||
} else {
|
||||
[[NSUserDefaults standardUserDefaults] removeObjectForKey:@"homeserver"];
|
||||
}
|
||||
[[NSUserDefaults standardUserDefaults] synchronize];
|
||||
}
|
||||
|
||||
- (NSString *)userLogin {
|
||||
return [[NSUserDefaults standardUserDefaults] objectForKey:@"userlogin"];
|
||||
}
|
||||
|
||||
- (void)setUserLogin:(NSString *)inUserLogin {
|
||||
if (inUserLogin.length) {
|
||||
[[NSUserDefaults standardUserDefaults] setObject:inUserLogin forKey:@"userlogin"];
|
||||
} else {
|
||||
[[NSUserDefaults standardUserDefaults] removeObjectForKey:@"userlogin"];
|
||||
}
|
||||
[[NSUserDefaults standardUserDefaults] synchronize];
|
||||
}
|
||||
|
||||
- (NSString *)userId {
|
||||
return [[NSUserDefaults standardUserDefaults] objectForKey:@"userid"];
|
||||
}
|
||||
|
||||
- (void)setUserId:(NSString *)inUserId {
|
||||
if (inUserId.length) {
|
||||
[[NSUserDefaults standardUserDefaults] setObject:inUserId forKey:@"userid"];
|
||||
|
||||
// Deduce local userid
|
||||
[[NSUserDefaults standardUserDefaults] removeObjectForKey:@"localuserid"];
|
||||
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"@(.*):\\w+" options:NSRegularExpressionCaseInsensitive error:nil];
|
||||
NSTextCheckingResult *match = [regex firstMatchInString:inUserId options:0 range:NSMakeRange(0, [inUserId length])];
|
||||
if (match.numberOfRanges == 2) {
|
||||
NSString* localId = [inUserId substringWithRange:[match rangeAtIndex:1]];
|
||||
if (localId) {
|
||||
[[NSUserDefaults standardUserDefaults] setObject:localId forKey:@"localuserid"];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
[[NSUserDefaults standardUserDefaults] removeObjectForKey:@"userid"];
|
||||
[[NSUserDefaults standardUserDefaults] removeObjectForKey:@"localuserid"];
|
||||
}
|
||||
[[NSUserDefaults standardUserDefaults] synchronize];
|
||||
}
|
||||
|
||||
- (NSString *)localPartFromUserId {
|
||||
return [[NSUserDefaults standardUserDefaults] objectForKey:@"localuserid"];
|
||||
}
|
||||
|
||||
- (NSString *)accessToken {
|
||||
return [[NSUserDefaults standardUserDefaults] objectForKey:@"accesstoken"];
|
||||
}
|
||||
|
||||
- (void)setAccessToken:(NSString *)inAccessToken {
|
||||
if (inAccessToken.length) {
|
||||
[[NSUserDefaults standardUserDefaults] setObject:inAccessToken forKey:@"accesstoken"];
|
||||
[[AppDelegate theDelegate] registerUserNotificationSettings];
|
||||
[self openSession];
|
||||
} else {
|
||||
[[NSUserDefaults standardUserDefaults] removeObjectForKey:@"accesstoken"];
|
||||
[self closeSession];
|
||||
}
|
||||
[[NSUserDefaults standardUserDefaults] synchronize];
|
||||
}
|
||||
|
||||
- (NSString *)identityServerURL {
|
||||
return [[NSUserDefaults standardUserDefaults] objectForKey:@"identityserverurl"];
|
||||
}
|
||||
|
||||
- (void)setIdentityServerURL:(NSString *)inIdentityServerURL {
|
||||
if (inIdentityServerURL.length) {
|
||||
[[NSUserDefaults standardUserDefaults] setObject:inIdentityServerURL forKey:@"identityserverurl"];
|
||||
} else {
|
||||
[[NSUserDefaults standardUserDefaults] removeObjectForKey:@"identityserverurl"];
|
||||
}
|
||||
[[NSUserDefaults standardUserDefaults] synchronize];
|
||||
|
||||
// Update the current restClient
|
||||
if (self.mxRestClient) {
|
||||
[self.mxRestClient setIdentityServer:self.identityServerURL];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Matrix user's settings
|
||||
|
||||
- (void)setUserPresence:(MXPresence)userPresence andStatusMessage:(NSString *)statusMessage completion:(void (^)(void))completion {
|
||||
self.userPresence = userPresence;
|
||||
// Update user presence on server side
|
||||
[self.mxSession.myUser setPresence:userPresence andStatusMessage:statusMessage success:^{
|
||||
NSLog(@"[MatrixHandler] Set user presence (%lu) succeeded", (unsigned long)userPresence);
|
||||
if (completion) {
|
||||
completion();
|
||||
}
|
||||
} failure:^(NSError *error) {
|
||||
NSLog(@"[MatrixHandler] Set user presence (%lu) failed: %@", (unsigned long)userPresence, error);
|
||||
}];
|
||||
}
|
||||
// FIXME GFO Move the following methods in SDK and Remove MatrixHandler class
|
||||
|
||||
#pragma mark - Room handling
|
||||
|
||||
|
@ -602,7 +98,7 @@ static MatrixHandler *sharedHandler = nil;
|
|||
topic:nil
|
||||
success:^(MXRoom *room) {
|
||||
// invite the other user only if it is defined and not onself
|
||||
if (userId && ![self.userId isEqualToString:userId]) {
|
||||
if (userId && ![self.mxSession.myUser.userId isEqualToString:userId]) {
|
||||
// add the user
|
||||
[room inviteUser:userId success:^{
|
||||
} failure:^(NSError *error) {
|
||||
|
@ -624,13 +120,6 @@ static MatrixHandler *sharedHandler = nil;
|
|||
}
|
||||
}
|
||||
|
||||
- (void)restoreInAppNotificationsForRoomId:(NSString*)roomID {
|
||||
if (roomID) {
|
||||
// Enable inApp notification for this room
|
||||
[self.unnotifiedRooms removeObject:roomID];
|
||||
}
|
||||
}
|
||||
|
||||
- (CGFloat)getPowerLevel:(MXRoomMember *)roomMember inRoom:(MXRoom *)room {
|
||||
CGFloat powerLevel = 0;
|
||||
|
||||
|
@ -680,17 +169,4 @@ static MatrixHandler *sharedHandler = nil;
|
|||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - KVO
|
||||
|
||||
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
|
||||
if ([@"showAllEventsInRoomHistory" isEqualToString:keyPath]) {
|
||||
// Flush and restore Matrix data
|
||||
[self reload:NO];
|
||||
}
|
||||
else if ([@"enableInAppNotifications" isEqualToString:keyPath]) {
|
||||
[self enableInAppNotifications:[[MXKAppSettings standardAppSettings] enableInAppNotifications]];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -194,7 +194,6 @@ static RageShakeManager* sharedInstance = nil;
|
|||
|
||||
NSString* appVersion = [AppDelegate theDelegate].appVersion;
|
||||
NSString* build = [AppDelegate theDelegate].build;
|
||||
MatrixHandler *mxHandler = [MatrixHandler sharedHandler];
|
||||
|
||||
NSMutableString* message = [[NSMutableString alloc] init];
|
||||
|
||||
|
@ -202,14 +201,18 @@ static RageShakeManager* sharedInstance = nil;
|
|||
|
||||
[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) {
|
||||
[message appendFormat:@"userId: %@\n", account.mxCredentials.userId];
|
||||
[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:@"userId: %@\n", mxHandler.userId];
|
||||
[message appendFormat:@"displayname: %@\n", mxHandler.mxSession.myUser.displayname];
|
||||
[message appendFormat:@"\n"];
|
||||
[message appendFormat:@"homeServerURL: %@\n", mxHandler.homeServerURL];
|
||||
[message appendFormat:@"homeServer: %@\n", mxHandler.homeServer];
|
||||
[message appendFormat:@"\n"];
|
||||
[message appendFormat:@"Console version: %@\n", appVersion];
|
||||
[message appendFormat:@"MatrixKit version: %@\n", MatrixKitVersion];
|
||||
[message appendFormat:@"MatrixSDK version: %@\n", MatrixSDKVersion];
|
||||
|
|
|
@ -38,6 +38,8 @@
|
|||
|
||||
- (void)registerUserNotificationSettings;
|
||||
|
||||
- (void)reloadMatrixSessions:(BOOL)clearCache;
|
||||
|
||||
- (void)logout;
|
||||
|
||||
- (MXKAlert*)showErrorAsAlert:(NSError*)error;
|
||||
|
|
|
@ -17,13 +17,14 @@
|
|||
#import "AppDelegate.h"
|
||||
#import "APNSHandler.h"
|
||||
#import "RoomViewController.h"
|
||||
#import "MatrixHandler.h"
|
||||
#import "SettingsViewController.h"
|
||||
#import "ContactManager.h"
|
||||
#import "RageShakeManager.h"
|
||||
|
||||
#import "AFNetworkReachabilityManager.h"
|
||||
|
||||
#import <AudioToolbox/AudioToolbox.h>
|
||||
|
||||
#define MAKE_STRING(x) #x
|
||||
#define MAKE_NS_STRING(x) @MAKE_STRING(x)
|
||||
|
||||
|
@ -33,8 +34,13 @@
|
|||
|
||||
// matrix session observer used to detect new opened sessions.
|
||||
id matrixSessionStateObserver;
|
||||
|
||||
// matrix account observer used to detect new added accounts.
|
||||
id matrixAccountsObserver;
|
||||
}
|
||||
|
||||
@property (strong, nonatomic) MXKAlert *mxInAppNotification;
|
||||
|
||||
@end
|
||||
|
||||
@implementation AppDelegate
|
||||
|
@ -103,6 +109,7 @@
|
|||
#pragma mark - UIApplicationDelegate
|
||||
|
||||
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
|
||||
|
||||
// Override point for customization after application launch.
|
||||
if ([self.window.rootViewController isKindOfClass:[MasterTabBarController class]])
|
||||
{
|
||||
|
@ -145,28 +152,8 @@
|
|||
[[NSUserDefaults standardUserDefaults] registerDefaults:defaults];
|
||||
[[NSUserDefaults standardUserDefaults] synchronize];
|
||||
|
||||
// Register matrix session state observer in order to handle new opened session
|
||||
matrixSessionStateObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXSessionStateDidChangeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
|
||||
|
||||
MXSession *mxSession = (MXSession*)notif.object;
|
||||
|
||||
// Check whether the concerned session is a new one
|
||||
if (mxSession.state == MXSessionStateInitialised) {
|
||||
|
||||
// Report this new session to contact manager
|
||||
[[ContactManager sharedManager] setMxSession:mxSession];
|
||||
|
||||
// Update all view controllers thanks to tab bar controller
|
||||
self.masterTabBarController.mxSession = mxSession;
|
||||
}
|
||||
}];
|
||||
|
||||
// Check whether we're logged in
|
||||
if ([MatrixHandler sharedHandler].accessToken) {
|
||||
[self registerUserNotificationSettings];
|
||||
// When user is already logged, we launch the app on Recents
|
||||
[self.masterTabBarController setSelectedIndex:TABBAR_RECENTS_INDEX];
|
||||
}
|
||||
// Add matrix observers and initialize matrix sessions.
|
||||
[self initMatrixSessions];
|
||||
}
|
||||
|
||||
// clear the notifications counter
|
||||
|
@ -192,10 +179,20 @@
|
|||
self.isOffline = NO;
|
||||
[[AFNetworkReachabilityManager sharedManager] stopMonitoring];
|
||||
|
||||
// check if some media msut be released to reduce the cache size
|
||||
// check if some media must be released to reduce the cache size
|
||||
[MXKMediaManager reduceCacheSizeToInsert:0];
|
||||
// Suspend Matrix handler
|
||||
[[MatrixHandler sharedHandler] pauseInBackgroundTask];
|
||||
|
||||
// Hide potential notification
|
||||
if (self.mxInAppNotification) {
|
||||
[self.mxInAppNotification dismiss:NO];
|
||||
self.mxInAppNotification = nil;
|
||||
}
|
||||
|
||||
// Suspend all running matrix sessions
|
||||
NSArray *mxAccounts = [MXKAccountManager sharedManager].accounts;
|
||||
for (MXKAccount *account in mxAccounts) {
|
||||
[account pauseInBackgroundTask];
|
||||
}
|
||||
|
||||
// clear the notifications counter
|
||||
[self clearNotifications];
|
||||
|
@ -217,8 +214,11 @@
|
|||
// Start monitoring reachability
|
||||
[[AFNetworkReachabilityManager sharedManager] startMonitoring];
|
||||
|
||||
// Resume Matrix handler
|
||||
[[MatrixHandler sharedHandler] resume];
|
||||
// Resume all existing matrix sessions
|
||||
NSArray *mxAccounts = [MXKAccountManager sharedManager].accounts;
|
||||
for (MXKAccount *account in mxAccounts) {
|
||||
[account resume];
|
||||
}
|
||||
|
||||
// refresh the contacts list
|
||||
[[ContactManager sharedManager] fullRefresh];
|
||||
|
@ -291,7 +291,95 @@
|
|||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark - Matrix sessions handling
|
||||
|
||||
- (void)initMatrixSessions {
|
||||
|
||||
// Register matrix session state observer in order to handle new opened session
|
||||
matrixSessionStateObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXSessionStateDidChangeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
|
||||
|
||||
MXSession *mxSession = (MXSession*)notif.object;
|
||||
|
||||
// Check whether the concerned session is a new one
|
||||
if (mxSession.state == MXSessionStateInitialised) {
|
||||
|
||||
// Report this new session to contact manager
|
||||
[[ContactManager sharedManager] setMxSession:mxSession];
|
||||
|
||||
// Update all view controllers thanks to tab bar controller
|
||||
self.masterTabBarController.mxSession = mxSession;
|
||||
|
||||
// Check whether the app user wants notifications on new events
|
||||
if ([[MXKAppSettings standardAppSettings] enableInAppNotifications]) {
|
||||
[self enableInAppNotifications:YES];
|
||||
}
|
||||
}
|
||||
}];
|
||||
|
||||
// Register an observer in order to handle new account
|
||||
matrixAccountsObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXKAccountManagerDidAddAccountNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
|
||||
|
||||
NSString *userId = (NSString*)notif.object;
|
||||
|
||||
// TODO GFO: handle here multi sessions
|
||||
|
||||
// Launch matrix session for this new account
|
||||
MXKAccount *account = [[MXKAccountManager sharedManager] accountForUserId:userId];
|
||||
if (account) {
|
||||
[self registerUserNotificationSettings];
|
||||
|
||||
// Use MXFileStore as MXStore to permanently store events.
|
||||
MXFileStore *mxFileStore = [[MXFileStore alloc] init];
|
||||
[account openSessionWithStore:mxFileStore];
|
||||
}
|
||||
}];
|
||||
|
||||
// Observe settings changes
|
||||
[[MXKAppSettings standardAppSettings] addObserver:self forKeyPath:@"enableInAppNotifications" options:0 context:nil];
|
||||
[[MXKAppSettings standardAppSettings] addObserver:self forKeyPath:@"showAllEventsInRoomHistory" options:0 context:nil];
|
||||
|
||||
// Check whether we're logged in
|
||||
NSArray *mxAccounts = [MXKAccountManager sharedManager].accounts;
|
||||
if (mxAccounts.count) {
|
||||
|
||||
[self registerUserNotificationSettings];
|
||||
|
||||
// When user is already logged, we launch the app on Recents
|
||||
[self.masterTabBarController setSelectedIndex:TABBAR_RECENTS_INDEX];
|
||||
|
||||
// Launch a matrix session only for the first account (TODO launch a session for each account).
|
||||
// Use MXFileStore as MXStore to permanently store events.
|
||||
MXFileStore *mxFileStore = [[MXFileStore alloc] init];
|
||||
[mxAccounts.firstObject openSessionWithStore:mxFileStore];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)reloadMatrixSessions:(BOOL)clearCache {
|
||||
|
||||
// Reload all running matrix sessions
|
||||
NSArray *mxAccounts = [MXKAccountManager sharedManager].accounts;
|
||||
for (MXKAccount *account in mxAccounts) {
|
||||
|
||||
if (account.mxSession) {
|
||||
id<MXStore> store = account.mxSession.store;
|
||||
|
||||
[[MXKRoomDataSourceManager sharedManagerForMatrixSession:account.mxSession] reset];
|
||||
|
||||
if (clearCache) {
|
||||
[store deleteAllData];
|
||||
}
|
||||
[account openSessionWithStore:store];
|
||||
}
|
||||
}
|
||||
|
||||
// Force back to Recents list if room details is displayed (Room details are not available until the end of initial sync)
|
||||
[self.masterTabBarController popRoomViewControllerAnimated:NO];
|
||||
|
||||
if (clearCache) {
|
||||
// clear the media cache
|
||||
[MXKMediaManager clearCache];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)logout {
|
||||
|
||||
|
@ -302,8 +390,8 @@
|
|||
// Clear cache
|
||||
[MXKMediaManager clearCache];
|
||||
|
||||
// Logout Matrix
|
||||
[[MatrixHandler sharedHandler] logout];
|
||||
// Logout all matrix account
|
||||
[[MXKAccountManager sharedManager] logout];
|
||||
|
||||
// Reset mxSession information in all view controllers
|
||||
self.masterTabBarController.mxSession = nil;
|
||||
|
@ -363,6 +451,87 @@
|
|||
[[UIApplication sharedApplication] cancelAllLocalNotifications];
|
||||
}
|
||||
|
||||
- (void)enableInAppNotifications:(BOOL)isEnabled {
|
||||
|
||||
// Update In-App notifications in all running matrix sessions
|
||||
NSArray *mxAccounts = [MXKAccountManager sharedManager].accounts;
|
||||
for (MXKAccount *account in mxAccounts) {
|
||||
|
||||
if (account.mxSession) {
|
||||
if (isEnabled) {
|
||||
// Build MXEvent -> NSString formatter
|
||||
MXKEventFormatter *eventFormatter = [[MXKEventFormatter alloc] initWithMatrixSession:account.mxSession];
|
||||
eventFormatter.isForSubtitle = YES;
|
||||
|
||||
[account listenToNotifications:^(MXEvent *event, MXRoomState *roomState, MXPushRule *rule) {
|
||||
|
||||
// Check conditions to display this notification (TODO GFO multi-session handling)
|
||||
if (![self.masterTabBarController.visibleRoomId isEqualToString:event.roomId]
|
||||
&& ![self.masterTabBarController isPresentingMediaPicker]) {
|
||||
|
||||
MXKEventFormatterError error;
|
||||
NSString* messageText = [eventFormatter stringFromEvent:event withRoomState:roomState error:&error];
|
||||
if (messageText.length && (error == MXKEventFormatterErrorNone)) {
|
||||
|
||||
// Removing existing notification (if any)
|
||||
if (self.mxInAppNotification) {
|
||||
[self.mxInAppNotification dismiss:NO];
|
||||
}
|
||||
|
||||
// Check whether tweak is required
|
||||
for (MXPushRuleAction *ruleAction in rule.actions) {
|
||||
if (ruleAction.actionType == MXPushRuleActionTypeSetTweak) {
|
||||
if ([[ruleAction.parameters valueForKey:@"set_tweak"] isEqualToString:@"sound"]) {
|
||||
// Play system sound (VoicemailReceived)
|
||||
AudioServicesPlaySystemSound (1002);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__weak typeof(self) weakSelf = self;
|
||||
self.mxInAppNotification = [[MXKAlert alloc] initWithTitle:roomState.displayname
|
||||
message:messageText
|
||||
style:MXKAlertStyleAlert];
|
||||
self.mxInAppNotification.cancelButtonIndex = [self.mxInAppNotification addActionWithTitle:@"Cancel"
|
||||
style:MXKAlertActionStyleDefault
|
||||
handler:^(MXKAlert *alert) {
|
||||
weakSelf.mxInAppNotification = nil;
|
||||
[account updateNotificationListenerForRoomId:event.roomId ignore:YES];
|
||||
}];
|
||||
[self.mxInAppNotification addActionWithTitle:@"View"
|
||||
style:MXKAlertActionStyleDefault
|
||||
handler:^(MXKAlert *alert) {
|
||||
weakSelf.mxInAppNotification = nil;
|
||||
// Show the room
|
||||
[weakSelf.masterTabBarController showRoom:event.roomId];
|
||||
}];
|
||||
|
||||
[self.mxInAppNotification showInViewController:[self.masterTabBarController selectedViewController]];
|
||||
}
|
||||
}
|
||||
}];
|
||||
} else {
|
||||
[account removeNotificationListener];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (self.mxInAppNotification) {
|
||||
[self.mxInAppNotification dismiss:NO];
|
||||
self.mxInAppNotification = nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
|
||||
if ([@"showAllEventsInRoomHistory" isEqualToString:keyPath]) {
|
||||
// Flush and restore Matrix data
|
||||
[self reloadMatrixSessions:NO];
|
||||
}
|
||||
else if ([@"enableInAppNotifications" isEqualToString:keyPath]) {
|
||||
[self enableInAppNotifications:[[MXKAppSettings standardAppSettings] enableInAppNotifications]];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - SplitViewController delegate
|
||||
|
||||
- (BOOL)splitViewController:(UISplitViewController *)splitViewController collapseSecondaryViewController:(UIViewController *)secondaryViewController ontoPrimaryViewController:(UIViewController *)primaryViewController {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="7531" systemVersion="14D131" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="GsA-m1-kGB">
|
||||
<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="7520"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6736"/>
|
||||
<capability name="Aspect ratio constraints" minToolsVersion="5.1"/>
|
||||
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
|
||||
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
|
||||
|
@ -587,433 +587,8 @@
|
|||
<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"/>
|
||||
<subviews>
|
||||
<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="udG-Mx-F4c">
|
||||
<rect key="frame" x="0.0" y="20" width="600" height="580"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="d6h-O8-aBs" userLabel="Content View">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="640"/>
|
||||
<subviews>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="logoHighRes.png" translatesAutoresizingMaskIntoConstraints="NO" id="9oD-IQ-d8J">
|
||||
<rect key="frame" x="180" y="33" width="240" height="102"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="240" id="YfR-TZ-HGu"/>
|
||||
<constraint firstAttribute="height" constant="102" id="qiX-ir-FRf"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
<label hidden="YES" opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Create account:" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="pvw-BQ-kaV">
|
||||
<rect key="frame" x="88" y="147" width="110" height="18"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="15"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="sQb-Oi-ER6" userLabel="AuthInputsContainerView">
|
||||
<rect key="frame" x="150" y="170" width="300" height="180"/>
|
||||
<subviews>
|
||||
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="O8N-hu-Ewh" userLabel="AuthInputsPasswordBasedView" customClass="AuthInputsPasswordBasedView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="300" height="179"/>
|
||||
<subviews>
|
||||
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="Matrix ID (e.g. @bob:matrix.org or bob)" textAlignment="center" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="DkI-2d-TR5">
|
||||
<rect key="frame" x="14" y="8" width="272" height="30"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="30" id="WJU-Hb-iFm"/>
|
||||
<constraint firstAttribute="width" constant="272" id="gzb-uu-iH0"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<textInputTraits key="textInputTraits" returnKeyType="next"/>
|
||||
<connections>
|
||||
<outlet property="delegate" destination="O8N-hu-Ewh" id="xI6-ue-Bbw"/>
|
||||
</connections>
|
||||
</textField>
|
||||
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="Password" textAlignment="center" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="gDT-bj-MHE">
|
||||
<rect key="frame" x="14" y="46" width="272" height="30"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="272" id="awG-2v-nb2"/>
|
||||
<constraint firstAttribute="height" constant="30" id="wHP-r9-WAA"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<textInputTraits key="textInputTraits" autocorrectionType="no" returnKeyType="done" secureTextEntry="YES"/>
|
||||
<connections>
|
||||
<outlet property="delegate" destination="O8N-hu-Ewh" id="enP-M1-s27"/>
|
||||
</connections>
|
||||
</textField>
|
||||
<textField hidden="YES" opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="Display name (e.g. Bob Obson)" textAlignment="center" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="Q4X-yt-15e" userLabel="DisplayName">
|
||||
<rect key="frame" x="14" y="84" width="272" height="30"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="272" id="A1t-Ov-vXU"/>
|
||||
<constraint firstAttribute="height" constant="30" id="RLA-my-oRJ"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<textInputTraits key="textInputTraits" autocorrectionType="no" returnKeyType="next" secureTextEntry="YES"/>
|
||||
<connections>
|
||||
<outlet property="delegate" destination="O8N-hu-Ewh" id="zHD-oq-zzj"/>
|
||||
</connections>
|
||||
</textField>
|
||||
<textField hidden="YES" opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="Email address (optional)" textAlignment="center" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="hnv-Gw-Cnj" userLabel="Email">
|
||||
<rect key="frame" x="14" y="126" width="272" height="30"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="30" id="IMW-ae-dUp"/>
|
||||
<constraint firstAttribute="width" constant="272" id="hKn-H5-T9d"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<textInputTraits key="textInputTraits" autocorrectionType="no" returnKeyType="done" secureTextEntry="YES"/>
|
||||
<connections>
|
||||
<outlet property="delegate" destination="O8N-hu-Ewh" id="F7K-1W-Nnc"/>
|
||||
</connections>
|
||||
</textField>
|
||||
<label hidden="YES" opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" preferredMaxLayoutWidth="0.0" translatesAutoresizingMaskIntoConstraints="NO" id="9ig-1b-AUZ" userLabel="EmailInfoLabel">
|
||||
<rect key="frame" x="14" y="156" width="272" height="15"/>
|
||||
<string key="text">Specify an email address lets other users find you on Matrix more easily, and will give you a way to reset your password in the future.</string>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="12"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="bottom" secondItem="9ig-1b-AUZ" secondAttribute="bottom" constant="8" id="7NI-xg-RWo"/>
|
||||
<constraint firstItem="gDT-bj-MHE" firstAttribute="top" secondItem="DkI-2d-TR5" secondAttribute="bottom" constant="8" id="DxY-3A-IYe"/>
|
||||
<constraint firstAttribute="centerX" secondItem="hnv-Gw-Cnj" secondAttribute="centerX" id="Ew9-Ir-5ZG"/>
|
||||
<constraint firstAttribute="centerX" secondItem="Q4X-yt-15e" secondAttribute="centerX" id="Fd9-Vj-hlF"/>
|
||||
<constraint firstItem="hnv-Gw-Cnj" firstAttribute="top" secondItem="Q4X-yt-15e" secondAttribute="bottom" constant="12" id="MWH-Pv-fFJ"/>
|
||||
<constraint firstItem="9ig-1b-AUZ" firstAttribute="leading" secondItem="O8N-hu-Ewh" secondAttribute="leading" constant="14" id="OYt-bj-cVD"/>
|
||||
<constraint firstAttribute="centerX" secondItem="gDT-bj-MHE" secondAttribute="centerX" id="PVZ-Fq-dKH"/>
|
||||
<constraint firstAttribute="trailing" secondItem="9ig-1b-AUZ" secondAttribute="trailing" constant="14" id="S77-1a-wps"/>
|
||||
<constraint firstItem="9ig-1b-AUZ" firstAttribute="top" secondItem="hnv-Gw-Cnj" secondAttribute="bottom" id="Soy-zj-uRP"/>
|
||||
<constraint firstItem="DkI-2d-TR5" firstAttribute="top" secondItem="O8N-hu-Ewh" secondAttribute="top" constant="8" id="VWB-qs-WRa"/>
|
||||
<constraint firstAttribute="centerX" secondItem="9ig-1b-AUZ" secondAttribute="centerX" id="dqb-WC-1x4"/>
|
||||
<constraint firstItem="Q4X-yt-15e" firstAttribute="top" secondItem="gDT-bj-MHE" secondAttribute="bottom" constant="8" id="fH8-wa-qMI"/>
|
||||
<constraint firstAttribute="width" constant="300" id="lGG-Df-1bn"/>
|
||||
<constraint firstAttribute="centerX" secondItem="DkI-2d-TR5" secondAttribute="centerX" id="sKP-5W-sQk"/>
|
||||
</constraints>
|
||||
<connections>
|
||||
<outlet property="displayNameTextField" destination="Q4X-yt-15e" id="WdS-ab-6Bv"/>
|
||||
<outlet property="emailInfoLabel" destination="9ig-1b-AUZ" id="dK0-5x-JgB"/>
|
||||
<outlet property="emailTextField" destination="hnv-Gw-Cnj" id="hsS-Rv-43G"/>
|
||||
<outlet property="passWordTextField" destination="gDT-bj-MHE" id="cqv-gD-CQe"/>
|
||||
<outlet property="userLoginTextField" destination="DkI-2d-TR5" id="1a2-ak-xgB"/>
|
||||
</connections>
|
||||
</view>
|
||||
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="G6Y-YQ-PvU" userLabel="AuthInputsEmailCodeBasedView" customClass="AuthInputsEmailCodeBasedView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="300" height="122"/>
|
||||
<subviews>
|
||||
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="Matrix ID (e.g. @bob:matrix.org or bob)" textAlignment="center" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="e5U-3R-SLf">
|
||||
<rect key="frame" x="14" y="8" width="272" height="30"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="30" id="dAe-Fy-Ro8"/>
|
||||
<constraint firstAttribute="width" constant="272" id="vJi-7m-V1p"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<textInputTraits key="textInputTraits" returnKeyType="next"/>
|
||||
<connections>
|
||||
<outlet property="delegate" destination="G6Y-YQ-PvU" id="SYJ-uu-LGE"/>
|
||||
</connections>
|
||||
</textField>
|
||||
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="Email address" textAlignment="center" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="E10-8t-uAc" userLabel="Email-Token">
|
||||
<rect key="frame" x="14" y="46" width="272" height="30"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="30" id="aSd-cp-L7s"/>
|
||||
<constraint firstAttribute="width" constant="272" id="szQ-eZ-pTJ"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<textInputTraits key="textInputTraits" autocorrectionType="no" returnKeyType="done" secureTextEntry="YES"/>
|
||||
<connections>
|
||||
<outlet property="delegate" destination="G6Y-YQ-PvU" id="LKy-hf-UiJ"/>
|
||||
</connections>
|
||||
</textField>
|
||||
<label hidden="YES" opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Please enter your email validation token:" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="EjR-UX-T9v">
|
||||
<rect key="frame" x="20" y="8" width="261" height="30"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<textField hidden="YES" opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="Display name (e.g. Bob Obson)" textAlignment="center" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="6Pu-F7-Xd3" userLabel="DisplayName">
|
||||
<rect key="frame" x="14" y="84" width="272" height="30"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="272" id="2UG-Lc-4TW"/>
|
||||
<constraint firstAttribute="height" constant="30" id="n5C-7V-kJk"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<textInputTraits key="textInputTraits" autocorrectionType="no" returnKeyType="done" secureTextEntry="YES"/>
|
||||
<connections>
|
||||
<outlet property="delegate" destination="G6Y-YQ-PvU" id="sdq-n3-nd8"/>
|
||||
</connections>
|
||||
</textField>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="centerX" secondItem="e5U-3R-SLf" secondAttribute="centerX" id="7C3-hj-pCD"/>
|
||||
<constraint firstItem="6Pu-F7-Xd3" firstAttribute="top" secondItem="E10-8t-uAc" secondAttribute="bottom" constant="8" id="Cu8-aC-0Ri"/>
|
||||
<constraint firstAttribute="centerX" secondItem="EjR-UX-T9v" secondAttribute="centerX" id="Utq-C1-03Y"/>
|
||||
<constraint firstItem="E10-8t-uAc" firstAttribute="top" secondItem="e5U-3R-SLf" secondAttribute="bottom" constant="8" id="VT1-qc-FBw"/>
|
||||
<constraint firstAttribute="centerX" secondItem="E10-8t-uAc" secondAttribute="centerX" id="XCM-Eo-2h5"/>
|
||||
<constraint firstAttribute="centerX" secondItem="6Pu-F7-Xd3" secondAttribute="centerX" id="bHU-Aa-fRf"/>
|
||||
<constraint firstAttribute="bottom" secondItem="6Pu-F7-Xd3" secondAttribute="bottom" constant="8" id="dmV-e8-Ak8"/>
|
||||
<constraint firstItem="E10-8t-uAc" firstAttribute="top" secondItem="EjR-UX-T9v" secondAttribute="bottom" constant="8" id="gwg-Ln-72n"/>
|
||||
<constraint firstItem="EjR-UX-T9v" firstAttribute="top" secondItem="G6Y-YQ-PvU" secondAttribute="top" constant="8" id="ktN-en-LeS"/>
|
||||
<constraint firstItem="e5U-3R-SLf" firstAttribute="top" secondItem="G6Y-YQ-PvU" secondAttribute="top" constant="8" id="pVD-lt-GF6"/>
|
||||
<constraint firstAttribute="width" constant="300" id="uor-7L-vf9"/>
|
||||
</constraints>
|
||||
<connections>
|
||||
<outlet property="displayNameTextField" destination="6Pu-F7-Xd3" id="dz7-PB-74N"/>
|
||||
<outlet property="emailAndTokenTextField" destination="E10-8t-uAc" id="vWQ-ED-DWS"/>
|
||||
<outlet property="promptEmailTokenLabel" destination="EjR-UX-T9v" id="4AO-pW-pp2"/>
|
||||
<outlet property="userLoginTextField" destination="e5U-3R-SLf" id="ywh-V7-6GX"/>
|
||||
</connections>
|
||||
</view>
|
||||
<activityIndicatorView hidden="YES" opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" style="gray" translatesAutoresizingMaskIntoConstraints="NO" id="J51-Cj-6mb">
|
||||
<rect key="frame" x="140" y="80" width="20" height="20"/>
|
||||
</activityIndicatorView>
|
||||
<label hidden="YES" opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Currently we do not support authentication flows defined by this Home Server" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" preferredMaxLayoutWidth="0.0" translatesAutoresizingMaskIntoConstraints="NO" id="eg7-eh-lZv" userLabel="noFlowLabel">
|
||||
<rect key="frame" x="9" y="8" width="283" height="17"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<color key="textColor" red="1" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<button hidden="YES" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="70b-I3-Cuk" userLabel="retryButton">
|
||||
<rect key="frame" x="128" y="30" width="45" height="30"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="45" id="4zv-VS-Uz6"/>
|
||||
<constraint firstAttribute="height" constant="30" id="eae-iR-11I"/>
|
||||
</constraints>
|
||||
<state key="normal" title="Retry">
|
||||
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="onButtonPressed:" destination="ZlD-EU-ncw" eventType="touchUpInside" id="VMc-vT-H6d"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="centerX" secondItem="70b-I3-Cuk" secondAttribute="centerX" id="2G2-j8-QdO"/>
|
||||
<constraint firstAttribute="centerY" secondItem="J51-Cj-6mb" secondAttribute="centerY" id="6R3-QL-izy"/>
|
||||
<constraint firstItem="G6Y-YQ-PvU" firstAttribute="top" secondItem="sQb-Oi-ER6" secondAttribute="top" id="7zC-MV-yX9"/>
|
||||
<constraint firstAttribute="centerX" secondItem="G6Y-YQ-PvU" secondAttribute="centerX" id="Eft-0W-r1l"/>
|
||||
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="eg7-eh-lZv" secondAttribute="trailing" constant="8" id="Ffa-SN-6DV"/>
|
||||
<constraint firstItem="eg7-eh-lZv" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="sQb-Oi-ER6" secondAttribute="leading" constant="8" id="NQi-Wl-keg"/>
|
||||
<constraint firstItem="O8N-hu-Ewh" firstAttribute="top" secondItem="sQb-Oi-ER6" secondAttribute="top" id="Qhd-nd-xQH"/>
|
||||
<constraint firstAttribute="centerX" secondItem="eg7-eh-lZv" secondAttribute="centerX" id="Rpn-e0-6X2"/>
|
||||
<constraint firstAttribute="centerX" secondItem="O8N-hu-Ewh" secondAttribute="centerX" id="eAO-Dq-dp1"/>
|
||||
<constraint firstItem="eg7-eh-lZv" firstAttribute="top" secondItem="sQb-Oi-ER6" secondAttribute="top" constant="8" id="fqE-nJ-QQK"/>
|
||||
<constraint firstAttribute="height" constant="180" id="gDV-QE-CXd"/>
|
||||
<constraint firstAttribute="centerX" secondItem="J51-Cj-6mb" secondAttribute="centerX" id="jiI-Qk-jML"/>
|
||||
<constraint firstItem="70b-I3-Cuk" firstAttribute="top" secondItem="eg7-eh-lZv" secondAttribute="bottom" constant="5" id="pGi-gI-AOX"/>
|
||||
<constraint firstAttribute="width" constant="300" id="xde-gy-DHI"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="fnl-LF-rEL" userLabel="SubmitBtn">
|
||||
<rect key="frame" x="273" y="360" width="55" height="33"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<state key="normal" title="Submit">
|
||||
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="onButtonPressed:" destination="ZlD-EU-ncw" eventType="touchUpInside" id="ER9-1w-3CL"/>
|
||||
</connections>
|
||||
</button>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="5a8-4J-rqy" userLabel="HomeServerView">
|
||||
<rect key="frame" x="124" y="408" width="352" height="30"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Home Server:" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="TW9-CJ-pH0">
|
||||
<rect key="frame" x="0.0" y="6" width="96" height="18"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="96" id="TVu-Hn-mwn"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="URL (e.g. https://matrix.org)" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="iBz-4w-0cv">
|
||||
<rect key="frame" x="102" y="0.0" width="250" height="30"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" priority="750" constant="250" id="3Jy-CR-r4b"/>
|
||||
<constraint firstAttribute="height" constant="30" id="waN-MT-6d2"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<textInputTraits key="textInputTraits" autocorrectionType="no" returnKeyType="done"/>
|
||||
<connections>
|
||||
<outlet property="delegate" destination="ZlD-EU-ncw" id="fJ9-39-2ag"/>
|
||||
</connections>
|
||||
</textField>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstItem="iBz-4w-0cv" firstAttribute="leading" secondItem="TW9-CJ-pH0" secondAttribute="trailing" constant="6" id="41G-OL-N3Z"/>
|
||||
<constraint firstItem="TW9-CJ-pH0" firstAttribute="top" secondItem="5a8-4J-rqy" secondAttribute="top" constant="6" id="IzW-2x-BS6"/>
|
||||
<constraint firstAttribute="bottom" secondItem="iBz-4w-0cv" secondAttribute="bottom" id="TXJ-ht-9MJ"/>
|
||||
<constraint firstAttribute="bottom" secondItem="TW9-CJ-pH0" secondAttribute="bottom" constant="6" id="YTz-Xx-gKA"/>
|
||||
<constraint firstAttribute="trailing" secondItem="iBz-4w-0cv" secondAttribute="trailing" id="YUC-u1-UJC"/>
|
||||
<constraint firstItem="iBz-4w-0cv" firstAttribute="top" secondItem="5a8-4J-rqy" secondAttribute="top" id="jpl-f7-eHN"/>
|
||||
<constraint firstItem="TW9-CJ-pH0" firstAttribute="leading" secondItem="5a8-4J-rqy" secondAttribute="leading" id="mXd-CX-Ehu"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Your home server stores all your conservation and account data." textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" preferredMaxLayoutWidth="0.0" translatesAutoresizingMaskIntoConstraints="NO" id="LKF-ef-JTA" userLabel="HomeServerInfoLabel">
|
||||
<rect key="frame" x="107" y="438" width="387" height="16"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="13"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="F4V-zC-19g" userLabel="IdentityServerView">
|
||||
<rect key="frame" x="119" y="462" width="363" height="30"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Identity Server:" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="MHk-DJ-BFj">
|
||||
<rect key="frame" x="0.0" y="6" width="107" height="18"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="107" id="JcY-aa-68S"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="URL (e.g. https://matrix.org)" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="yfy-fB-piy">
|
||||
<rect key="frame" x="113" y="0.0" width="250" height="30"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="30" id="1F5-e4-bJG"/>
|
||||
<constraint firstAttribute="width" priority="750" constant="250" id="l5u-xy-hOo"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<textInputTraits key="textInputTraits" autocorrectionType="no" returnKeyType="done"/>
|
||||
<connections>
|
||||
<outlet property="delegate" destination="ZlD-EU-ncw" id="7a0-Jw-Wg8"/>
|
||||
</connections>
|
||||
</textField>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="bottom" secondItem="MHk-DJ-BFj" secondAttribute="bottom" constant="6" id="FAd-Dl-1I7"/>
|
||||
<constraint firstAttribute="trailing" secondItem="yfy-fB-piy" secondAttribute="trailing" id="Vcv-Uh-OAO"/>
|
||||
<constraint firstItem="yfy-fB-piy" firstAttribute="top" secondItem="F4V-zC-19g" secondAttribute="top" id="ek8-U6-AJf"/>
|
||||
<constraint firstItem="yfy-fB-piy" firstAttribute="leading" secondItem="MHk-DJ-BFj" secondAttribute="trailing" constant="6" id="qQD-zl-EVh"/>
|
||||
<constraint firstAttribute="bottom" secondItem="yfy-fB-piy" secondAttribute="bottom" id="sVj-ei-7Yd"/>
|
||||
<constraint firstItem="MHk-DJ-BFj" firstAttribute="leading" secondItem="F4V-zC-19g" secondAttribute="leading" id="tvn-1T-DLz"/>
|
||||
<constraint firstItem="MHk-DJ-BFj" firstAttribute="top" secondItem="F4V-zC-19g" secondAttribute="top" constant="6" id="xHO-pQ-fCR"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" preferredMaxLayoutWidth="0.0" translatesAutoresizingMaskIntoConstraints="NO" id="0ot-Cn-Okj" userLabel="IdentityServerInfoLabel">
|
||||
<rect key="frame" x="8" y="492" width="584" height="16"/>
|
||||
<string key="text">Matrix provides identity servers to track which emails etc. belong to which Matrix IDs. Only https://matrix.org currently exists.</string>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="13"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="bYl-BD-hfc" userLabel="authSwitchButton">
|
||||
<rect key="frame" x="248" y="520" width="105" height="30"/>
|
||||
<state key="normal" title="Create account">
|
||||
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="onButtonPressed:" destination="ZlD-EU-ncw" eventType="touchUpInside" id="MWy-Uy-9Nc"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="centerX" secondItem="0ot-Cn-Okj" secondAttribute="centerX" id="01i-Qj-xeO"/>
|
||||
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="5a8-4J-rqy" secondAttribute="trailing" constant="8" id="0M5-HS-blg"/>
|
||||
<constraint firstAttribute="height" constant="640" id="42v-uQ-LsL"/>
|
||||
<constraint firstAttribute="centerX" secondItem="LKF-ef-JTA" secondAttribute="centerX" id="69A-yA-IEW"/>
|
||||
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="F4V-zC-19g" secondAttribute="trailing" constant="8" id="8ab-Z4-kg9"/>
|
||||
<constraint firstItem="5a8-4J-rqy" firstAttribute="top" secondItem="fnl-LF-rEL" secondAttribute="bottom" constant="15" id="BDw-eQ-BRA"/>
|
||||
<constraint firstItem="0ot-Cn-Okj" firstAttribute="top" secondItem="F4V-zC-19g" secondAttribute="bottom" id="INC-BK-58n"/>
|
||||
<constraint firstAttribute="centerX" secondItem="9oD-IQ-d8J" secondAttribute="centerX" id="JLJ-dk-JdK"/>
|
||||
<constraint firstAttribute="centerX" secondItem="5a8-4J-rqy" secondAttribute="centerX" id="L9E-M9-JZR"/>
|
||||
<constraint firstAttribute="centerX" secondItem="pvw-BQ-kaV" secondAttribute="centerX" multiplier="2.1" id="PQx-8d-2WE"/>
|
||||
<constraint firstAttribute="centerX" secondItem="fnl-LF-rEL" secondAttribute="centerX" id="Sgz-AH-2EN"/>
|
||||
<constraint firstItem="5a8-4J-rqy" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="d6h-O8-aBs" secondAttribute="leading" constant="8" id="VRZ-uz-BCX"/>
|
||||
<constraint firstItem="F4V-zC-19g" firstAttribute="top" secondItem="LKF-ef-JTA" secondAttribute="bottom" constant="8" id="YYC-7e-ggI"/>
|
||||
<constraint firstItem="LKF-ef-JTA" firstAttribute="top" secondItem="5a8-4J-rqy" secondAttribute="bottom" id="arP-7h-TB2"/>
|
||||
<constraint firstAttribute="width" constant="600" placeholder="YES" id="b29-CD-6mb"/>
|
||||
<constraint firstItem="sQb-Oi-ER6" firstAttribute="top" secondItem="pvw-BQ-kaV" secondAttribute="bottom" constant="5" id="dUA-me-Oly"/>
|
||||
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="0ot-Cn-Okj" secondAttribute="trailing" constant="8" id="gz6-Ih-fPV"/>
|
||||
<constraint firstItem="fnl-LF-rEL" firstAttribute="top" secondItem="sQb-Oi-ER6" secondAttribute="bottom" constant="10" id="icu-FA-ijI"/>
|
||||
<constraint firstItem="0ot-Cn-Okj" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="d6h-O8-aBs" secondAttribute="leading" constant="8" id="lBq-aj-naj"/>
|
||||
<constraint firstItem="bYl-BD-hfc" firstAttribute="top" secondItem="0ot-Cn-Okj" secondAttribute="bottom" constant="12" id="lbG-dp-rtx"/>
|
||||
<constraint firstItem="LKF-ef-JTA" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="d6h-O8-aBs" secondAttribute="leading" constant="8" id="pn0-tX-vwe"/>
|
||||
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="LKF-ef-JTA" secondAttribute="trailing" constant="8" id="prS-UK-oXJ"/>
|
||||
<constraint firstAttribute="centerX" secondItem="bYl-BD-hfc" secondAttribute="centerX" id="rLh-01-K2X"/>
|
||||
<constraint firstAttribute="centerX" secondItem="F4V-zC-19g" secondAttribute="centerX" id="wgS-c7-SWD"/>
|
||||
<constraint firstItem="sQb-Oi-ER6" firstAttribute="top" secondItem="9oD-IQ-d8J" secondAttribute="bottom" constant="35" id="whU-LM-RDN"/>
|
||||
<constraint firstAttribute="centerX" secondItem="sQb-Oi-ER6" secondAttribute="centerX" id="xGd-ig-cIb"/>
|
||||
<constraint firstItem="sQb-Oi-ER6" firstAttribute="top" secondItem="d6h-O8-aBs" secondAttribute="top" constant="170" id="ynf-Lz-N7e"/>
|
||||
<constraint firstItem="F4V-zC-19g" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="d6h-O8-aBs" secondAttribute="leading" constant="8" id="zTN-SN-HQK"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstItem="d6h-O8-aBs" firstAttribute="leading" secondItem="udG-Mx-F4c" secondAttribute="leading" id="0AZ-PL-Sqy"/>
|
||||
<constraint firstItem="d6h-O8-aBs" firstAttribute="top" secondItem="udG-Mx-F4c" secondAttribute="top" id="qxm-bJ-sOv"/>
|
||||
<constraint firstAttribute="trailing" secondItem="d6h-O8-aBs" secondAttribute="trailing" id="xYP-vJ-Pau"/>
|
||||
<constraint firstAttribute="bottom" secondItem="d6h-O8-aBs" secondAttribute="bottom" id="zJF-4I-K30"/>
|
||||
</constraints>
|
||||
</scrollView>
|
||||
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="m1P-2H-e3q" userLabel="RegistrationFallbackContentView">
|
||||
<rect key="frame" x="0.0" y="20" width="600" height="580"/>
|
||||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Wy8-eL-0qs">
|
||||
<rect key="frame" x="542" y="5" width="50" height="35"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="50" id="SNe-ts-mx1"/>
|
||||
<constraint firstAttribute="height" constant="35" id="cxj-k5-5eB"/>
|
||||
</constraints>
|
||||
<state key="normal" title="Cancel">
|
||||
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="onButtonPressed:" destination="ZlD-EU-ncw" eventType="touchUpInside" id="Z6U-iX-emw"/>
|
||||
</connections>
|
||||
</button>
|
||||
<webView contentMode="scaleToFill" scalesPageToFit="YES" translatesAutoresizingMaskIntoConstraints="NO" id="zwS-9o-UR1" userLabel="registrationWebView" customClass="MXCRegistrationWebView">
|
||||
<rect key="frame" x="0.0" y="40" width="600" height="540"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</webView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstItem="zwS-9o-UR1" firstAttribute="leading" secondItem="m1P-2H-e3q" secondAttribute="leading" id="PdC-BM-cGq"/>
|
||||
<constraint firstItem="zwS-9o-UR1" firstAttribute="top" secondItem="Wy8-eL-0qs" secondAttribute="bottom" id="SHg-kb-HYZ"/>
|
||||
<constraint firstAttribute="trailing" secondItem="Wy8-eL-0qs" secondAttribute="trailing" constant="8" id="dAE-oR-gyO"/>
|
||||
<constraint firstItem="Wy8-eL-0qs" firstAttribute="top" secondItem="m1P-2H-e3q" secondAttribute="top" constant="5" id="jN2-LM-zDK"/>
|
||||
<constraint firstAttribute="bottom" secondItem="zwS-9o-UR1" secondAttribute="bottom" id="mcB-1V-H10"/>
|
||||
<constraint firstAttribute="trailing" secondItem="zwS-9o-UR1" secondAttribute="trailing" id="pET-Lk-c56"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstItem="m1P-2H-e3q" firstAttribute="top" secondItem="crg-iM-twR" secondAttribute="bottom" id="4H8-cd-dqk"/>
|
||||
<constraint firstAttribute="trailing" secondItem="udG-Mx-F4c" secondAttribute="trailing" id="A3Y-Nc-49v"/>
|
||||
<constraint firstItem="gbK-Nm-HUT" firstAttribute="top" secondItem="udG-Mx-F4c" secondAttribute="bottom" id="CT4-Dg-1Dx"/>
|
||||
<constraint firstItem="gbK-Nm-HUT" firstAttribute="top" secondItem="m1P-2H-e3q" secondAttribute="bottom" id="TvL-CC-lFt"/>
|
||||
<constraint firstItem="udG-Mx-F4c" firstAttribute="leading" secondItem="wIi-Yi-2pi" secondAttribute="leading" id="gtx-Th-HKc"/>
|
||||
<constraint firstAttribute="trailing" secondItem="m1P-2H-e3q" secondAttribute="trailing" id="hGg-r7-gFx"/>
|
||||
<constraint firstItem="m1P-2H-e3q" firstAttribute="leading" secondItem="wIi-Yi-2pi" secondAttribute="leading" id="jyc-F5-4sW"/>
|
||||
<constraint firstItem="udG-Mx-F4c" firstAttribute="top" secondItem="wIi-Yi-2pi" secondAttribute="top" constant="20" symbolic="YES" id="ku3-Lq-Cxe"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<connections>
|
||||
<outlet property="authInputContainerViewHeightConstraint" destination="gDV-QE-CXd" id="w2j-CW-jC6"/>
|
||||
<outlet property="authInputsContainerView" destination="sQb-Oi-ER6" id="16R-BA-8pJ"/>
|
||||
<outlet property="authInputsEmailCodeBasedView" destination="G6Y-YQ-PvU" id="8IM-sx-LeP"/>
|
||||
<outlet property="authInputsPasswordBasedView" destination="O8N-hu-Ewh" id="1ZN-jj-Txd"/>
|
||||
<outlet property="authSwitchButton" destination="bYl-BD-hfc" id="RmX-1U-gbu"/>
|
||||
<outlet property="authenticationActivityIndicator" destination="J51-Cj-6mb" id="kKy-b0-RS1"/>
|
||||
<outlet property="authenticationScrollView" destination="udG-Mx-F4c" id="tzx-0l-1q0"/>
|
||||
<outlet property="cancelRegistrationFallbackButton" destination="Wy8-eL-0qs" id="zDb-ys-RHw"/>
|
||||
<outlet property="contentView" destination="d6h-O8-aBs" id="hId-Ic-rv4"/>
|
||||
<outlet property="contentViewHeightConstraint" destination="42v-uQ-LsL" id="d3Y-uv-J8T"/>
|
||||
<outlet property="createAccountLabel" destination="pvw-BQ-kaV" id="HvM-wg-gEw"/>
|
||||
<outlet property="homeServerInfoLabel" destination="LKF-ef-JTA" id="0EM-71-189"/>
|
||||
<outlet property="homeServerTextField" destination="iBz-4w-0cv" id="mPB-je-wz5"/>
|
||||
<outlet property="identityServerInfoLabel" destination="0ot-Cn-Okj" id="fch-En-eR0"/>
|
||||
<outlet property="identityServerTextField" destination="yfy-fB-piy" id="gwN-t1-TX9"/>
|
||||
<outlet property="noFlowLabel" destination="eg7-eh-lZv" id="eQi-Nt-5Ik"/>
|
||||
<outlet property="registrationFallbackContentView" destination="m1P-2H-e3q" id="cTq-S4-f9R"/>
|
||||
<outlet property="registrationFallbackWebView" destination="zwS-9o-UR1" id="7g9-vt-riy"/>
|
||||
<outlet property="retryButton" destination="70b-I3-Cuk" id="jHb-ZS-hrR"/>
|
||||
<outlet property="submitButton" destination="fnl-LF-rEL" id="a9E-g2-2C2"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="mvZ-se-pqQ" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
|
@ -1647,7 +1222,6 @@
|
|||
<resources>
|
||||
<image name="default-profile.png" width="160" height="160"/>
|
||||
<image name="icon_users.png" width="35" height="25"/>
|
||||
<image name="logoHighRes.png" width="480" height="204"/>
|
||||
<image name="matrixUser.png" width="16" height="16"/>
|
||||
<image name="tab_home.ico" width="16" height="16"/>
|
||||
<image name="tab_settings.png" width="25" height="25"/>
|
||||
|
|
|
@ -1,60 +0,0 @@
|
|||
/*
|
||||
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>
|
||||
|
||||
// Authentication type: register or login
|
||||
typedef enum {
|
||||
AuthenticationTypeRegister,
|
||||
AuthenticationTypeLogin
|
||||
}
|
||||
AuthenticationType;
|
||||
|
||||
@class AuthInputsView;
|
||||
|
||||
@protocol AuthInputsViewDelegate <NSObject>
|
||||
@optional
|
||||
- (void)authInputsDoneKeyHasBeenPressed:(AuthInputsView *)authInputsView;
|
||||
@end
|
||||
|
||||
@interface AuthInputsView : UIView <UITextFieldDelegate>
|
||||
|
||||
@property (nonatomic) AuthenticationType authType;
|
||||
@property (nonatomic) id <AuthInputsViewDelegate> delegate;
|
||||
// Optional fields added in case of registration
|
||||
@property (weak, nonatomic) IBOutlet UITextField *displayNameTextField;
|
||||
|
||||
- (CGFloat)actualHeight;
|
||||
- (BOOL)areAllRequiredFieldsFilled;
|
||||
- (void)dismissKeyboard;
|
||||
|
||||
- (void)nextStep;
|
||||
- (void)resetStep;
|
||||
@end
|
||||
|
||||
@interface AuthInputsPasswordBasedView : AuthInputsView
|
||||
@property (weak, nonatomic) IBOutlet UITextField *userLoginTextField;
|
||||
@property (weak, nonatomic) IBOutlet UITextField *passWordTextField;
|
||||
// Optional fields added in case of registration
|
||||
@property (weak, nonatomic) IBOutlet UITextField *emailTextField;
|
||||
@property (weak, nonatomic) IBOutlet UILabel *emailInfoLabel;
|
||||
@end
|
||||
|
||||
@interface AuthInputsEmailCodeBasedView : AuthInputsView
|
||||
@property (weak, nonatomic) IBOutlet UITextField *userLoginTextField;
|
||||
@property (weak, nonatomic) IBOutlet UITextField *emailAndTokenTextField;
|
||||
@property (weak, nonatomic) IBOutlet UILabel *promptEmailTokenLabel;
|
||||
@end
|
|
@ -1,209 +0,0 @@
|
|||
/*
|
||||
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 "AuthInputsView.h"
|
||||
#import "MatrixHandler.h"
|
||||
|
||||
@implementation AuthInputsView
|
||||
|
||||
- (CGFloat)actualHeight {
|
||||
return self.frame.size.height;
|
||||
}
|
||||
|
||||
- (BOOL)areAllRequiredFieldsFilled {
|
||||
// Currently no field to check here
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)setAuthType:(AuthenticationType)authType {
|
||||
if (authType == AuthenticationTypeLogin) {
|
||||
self.displayNameTextField.hidden = YES;
|
||||
} else {
|
||||
self.displayNameTextField.hidden = NO;
|
||||
}
|
||||
_authType = authType;
|
||||
}
|
||||
|
||||
- (void)dismissKeyboard {
|
||||
[self.displayNameTextField resignFirstResponder];
|
||||
}
|
||||
|
||||
- (void)nextStep {
|
||||
self.displayNameTextField.hidden = YES;
|
||||
}
|
||||
|
||||
- (void)resetStep {
|
||||
self.authType = _authType;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - AuthInputsPasswordBasedView
|
||||
|
||||
@implementation AuthInputsPasswordBasedView
|
||||
|
||||
- (CGFloat)actualHeight {
|
||||
if (self.authType == AuthenticationTypeLogin) {
|
||||
return self.displayNameTextField.frame.origin.y;
|
||||
}
|
||||
return super.actualHeight;
|
||||
}
|
||||
|
||||
- (BOOL)areAllRequiredFieldsFilled {
|
||||
BOOL ret = [super areAllRequiredFieldsFilled];
|
||||
|
||||
// Check user login and pass fields
|
||||
ret = (ret && self.userLoginTextField.text.length && self.passWordTextField.text.length);
|
||||
return ret;
|
||||
}
|
||||
|
||||
- (void)setAuthType:(AuthenticationType)authType {
|
||||
if (authType == AuthenticationTypeLogin) {
|
||||
self.passWordTextField.returnKeyType = UIReturnKeyDone;
|
||||
self.emailTextField.hidden = YES;
|
||||
self.emailInfoLabel.hidden = YES;
|
||||
} else {
|
||||
self.passWordTextField.returnKeyType = UIReturnKeyNext;
|
||||
self.emailTextField.hidden = NO;
|
||||
self.emailInfoLabel.hidden = NO;
|
||||
}
|
||||
super.authType = authType;
|
||||
|
||||
// Prefill text field
|
||||
self.userLoginTextField.text = [[MatrixHandler sharedHandler] userLogin];
|
||||
self.passWordTextField.text = nil;
|
||||
}
|
||||
|
||||
- (void)dismissKeyboard {
|
||||
[self.userLoginTextField resignFirstResponder];
|
||||
[self.passWordTextField resignFirstResponder];
|
||||
[self.emailTextField resignFirstResponder];
|
||||
|
||||
[super dismissKeyboard];
|
||||
}
|
||||
|
||||
#pragma mark UITextField delegate
|
||||
|
||||
- (void)textFieldDidEndEditing:(UITextField *)textField {
|
||||
if (textField == self.userLoginTextField) {
|
||||
[[MatrixHandler sharedHandler] setUserLogin:textField.text];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)textFieldShouldReturn:(UITextField*)textField {
|
||||
if (textField.returnKeyType == UIReturnKeyDone) {
|
||||
// "Done" key has been pressed
|
||||
[textField resignFirstResponder];
|
||||
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(authInputsDoneKeyHasBeenPressed:)]) {
|
||||
// Launch authentication now
|
||||
[self.delegate authInputsDoneKeyHasBeenPressed:self];
|
||||
}
|
||||
} else {
|
||||
//"Next" key has been pressed
|
||||
if (textField == self.userLoginTextField) {
|
||||
[self.passWordTextField becomeFirstResponder];
|
||||
} else if (textField == self.passWordTextField) {
|
||||
[self.displayNameTextField becomeFirstResponder];
|
||||
} else if (textField == self.displayNameTextField) {
|
||||
[self.emailTextField becomeFirstResponder];
|
||||
}
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
@end
|
||||
|
||||
#pragma mark - AuthInputsEmailCodeBasedView
|
||||
|
||||
@implementation AuthInputsEmailCodeBasedView
|
||||
|
||||
- (CGFloat)actualHeight {
|
||||
if (self.authType == AuthenticationTypeLogin) {
|
||||
return self.displayNameTextField.frame.origin.y;
|
||||
}
|
||||
return super.actualHeight;
|
||||
}
|
||||
|
||||
- (BOOL)areAllRequiredFieldsFilled {
|
||||
BOOL ret = [super areAllRequiredFieldsFilled];
|
||||
|
||||
// Check required fields //FIXME what are required fields in this authentication flow?
|
||||
ret = (ret && self.userLoginTextField.text.length && self.emailAndTokenTextField.text.length);
|
||||
return ret;
|
||||
}
|
||||
|
||||
- (void)setAuthType:(AuthenticationType)authType {
|
||||
// Set initial layout
|
||||
self.userLoginTextField.hidden = NO;
|
||||
self.promptEmailTokenLabel.hidden = YES;
|
||||
|
||||
if (authType == AuthenticationTypeLogin) {
|
||||
self.emailAndTokenTextField.returnKeyType = UIReturnKeyDone;
|
||||
} else {
|
||||
self.emailAndTokenTextField.returnKeyType = UIReturnKeyNext;
|
||||
}
|
||||
|
||||
super.authType = authType;
|
||||
}
|
||||
|
||||
- (void)dismissKeyboard {
|
||||
[self.userLoginTextField resignFirstResponder];
|
||||
[self.emailAndTokenTextField resignFirstResponder];
|
||||
|
||||
[super dismissKeyboard];
|
||||
}
|
||||
|
||||
- (void)nextStep {
|
||||
// Consider here the email token has been requested with success
|
||||
[super nextStep];
|
||||
|
||||
self.userLoginTextField.hidden = YES;
|
||||
self.promptEmailTokenLabel.hidden = NO;
|
||||
self.emailAndTokenTextField.returnKeyType = UIReturnKeyDone;
|
||||
}
|
||||
|
||||
#pragma mark UITextField delegate
|
||||
|
||||
- (void)textFieldDidEndEditing:(UITextField *)textField {
|
||||
if (textField == self.userLoginTextField) {
|
||||
[[MatrixHandler sharedHandler] setUserLogin:textField.text];
|
||||
}
|
||||
// FIXME store user's email in matrixSDKHandler like userId
|
||||
}
|
||||
|
||||
- (BOOL)textFieldShouldReturn:(UITextField*)textField {
|
||||
if (textField.returnKeyType == UIReturnKeyDone) {
|
||||
// "Done" key has been pressed
|
||||
[textField resignFirstResponder];
|
||||
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(authInputsDoneKeyHasBeenPressed:)]) {
|
||||
// Launch authentication now
|
||||
[self.delegate authInputsDoneKeyHasBeenPressed:self];
|
||||
}
|
||||
} else {
|
||||
//"Next" key has been pressed
|
||||
if (textField == self.userLoginTextField) {
|
||||
[self.emailAndTokenTextField becomeFirstResponder];
|
||||
} else if (textField == self.emailAndTokenTextField) {
|
||||
[self.displayNameTextField becomeFirstResponder];
|
||||
}
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
|
@ -1,31 +0,0 @@
|
|||
/*
|
||||
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>
|
||||
|
||||
#include <MXRestClient.h>
|
||||
|
||||
@interface MXCRegistrationWebView : UIWebView <UIWebViewDelegate>
|
||||
|
||||
/**
|
||||
Open a registration fallback page into the webview.
|
||||
|
||||
@param fallbackPage the fallback page hosted by a home server.
|
||||
@param success the block called when the user has been successfully registered.
|
||||
*/
|
||||
- (void)openFallbackPage:(NSString*)fallbackPage success:(void (^)(MXCredentials *credentials))success;
|
||||
|
||||
@end
|
|
@ -1,106 +0,0 @@
|
|||
/*
|
||||
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 "MXCRegistrationWebView.h"
|
||||
|
||||
// Generic method to make a bridge between JS and the UIWebView
|
||||
NSString *kMXCJavascriptSendObjectMessage = @"window.matrixRegistration.sendObjectMessage = function(parameters) { \
|
||||
var iframe = document.createElement('iframe'); \
|
||||
iframe.setAttribute('src', 'js:' + JSON.stringify(parameters)); \
|
||||
\
|
||||
document.documentElement.appendChild(iframe); \
|
||||
iframe.parentNode.removeChild(iframe); \
|
||||
iframe = null; \
|
||||
};";
|
||||
|
||||
// The function the fallback page calls when the registration is complete
|
||||
NSString *kMXCJavascriptOnRegistered = @"window.matrixRegistration.onRegistered = function(homeserverUrl, userId, accessToken) { \
|
||||
matrixRegistration.sendObjectMessage({ \
|
||||
'action': 'onRegistered', \
|
||||
'homeServer': homeserverUrl, \
|
||||
'userId': userId, \
|
||||
'accessToken': accessToken \
|
||||
}); \
|
||||
};";
|
||||
|
||||
@interface MXCRegistrationWebView () {
|
||||
// The block called when the registration is successful
|
||||
void (^onSuccess)(MXCredentials *);
|
||||
|
||||
// Activity indicator
|
||||
UIActivityIndicatorView *activityIndicator;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation MXCRegistrationWebView
|
||||
|
||||
- (void)dealloc {
|
||||
if (activityIndicator) {
|
||||
[activityIndicator removeFromSuperview];
|
||||
activityIndicator = nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)openFallbackPage:(NSString *)fallbackPage success:(void (^)(MXCredentials *))success {
|
||||
self.delegate = self;
|
||||
onSuccess = success;
|
||||
|
||||
// Add activity indicator
|
||||
activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
|
||||
activityIndicator.center = self.center;
|
||||
[self addSubview:activityIndicator];
|
||||
[activityIndicator startAnimating];
|
||||
|
||||
[self loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:fallbackPage]]];
|
||||
}
|
||||
|
||||
-(void)webViewDidFinishLoad:(UIWebView *)webView {
|
||||
if (activityIndicator) {
|
||||
[activityIndicator stopAnimating];
|
||||
[activityIndicator removeFromSuperview];
|
||||
activityIndicator = nil;
|
||||
}
|
||||
|
||||
[self stringByEvaluatingJavaScriptFromString:kMXCJavascriptSendObjectMessage];
|
||||
[self stringByEvaluatingJavaScriptFromString:kMXCJavascriptOnRegistered];
|
||||
}
|
||||
|
||||
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
|
||||
NSString *urlString = [[request URL] absoluteString];
|
||||
|
||||
if ([urlString hasPrefix:@"js:"]) {
|
||||
// Listen only to scheme of the JS-UIWebView bridge
|
||||
NSString *jsonString = [[[urlString componentsSeparatedByString:@"js:"] lastObject] stringByReplacingPercentEscapesUsingEncoding:NSASCIIStringEncoding];
|
||||
NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
|
||||
|
||||
NSError *error;
|
||||
NSDictionary *parameters = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers
|
||||
error:&error];
|
||||
|
||||
if (!error) {
|
||||
if ([@"onRegistered" isEqualToString:parameters[@"action"]]) {
|
||||
// Translate the JS registration event to MXCredentials
|
||||
MXCredentials *credentials = [[MXCredentials alloc] initWithHomeServer:parameters[@"homeServer"] userId:parameters[@"userId"] accessToken:parameters[@"accessToken"]];
|
||||
// And inform the client
|
||||
onSuccess(credentials);
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
|
@ -16,9 +16,7 @@
|
|||
|
||||
#import <MatrixKit/MatrixKit.h>
|
||||
|
||||
#import "AuthInputsView.h"
|
||||
|
||||
@interface AuthenticationViewController : MXKViewController <UITextFieldDelegate, AuthInputsViewDelegate>
|
||||
@interface AuthenticationViewController : MXKAuthenticationViewController <MXKAuthenticationViewControllerDelegate>
|
||||
|
||||
@end
|
||||
|
||||
|
|
|
@ -16,563 +16,37 @@
|
|||
|
||||
#import "AuthenticationViewController.h"
|
||||
|
||||
#import "MatrixHandler.h"
|
||||
#import "AppDelegate.h"
|
||||
#import "MXCRegistrationWebView.h"
|
||||
|
||||
#import "RageShakeManager.h"
|
||||
|
||||
@interface AuthenticationViewController () {
|
||||
// Current request in progress
|
||||
MXHTTPOperation *mxCurrentOperation;
|
||||
|
||||
// Array of flows supported by the home server and implemented by the app (for the current auth type)
|
||||
NSMutableArray *supportedFlows;
|
||||
|
||||
// The current view in which auth inputs are displayed
|
||||
AuthInputsView *currentAuthInputsView;
|
||||
|
||||
// reference to any opened alert view
|
||||
MXKAlert *alert;
|
||||
}
|
||||
|
||||
// Return true if the provided flow (kMXLoginFlowType) is supported by the application
|
||||
+ (BOOL)isImplementedFlowType:(NSString*)flowType forAuthType:(AuthenticationType)authType;
|
||||
|
||||
// The current authentication type
|
||||
@property (nonatomic) AuthenticationType authType;
|
||||
@property (nonatomic) MXLoginFlow *selectedFlow;
|
||||
|
||||
@property (strong, nonatomic) IBOutlet UIScrollView *authenticationScrollView;
|
||||
@property (weak, nonatomic) IBOutlet UIView *contentView;
|
||||
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *contentViewHeightConstraint;
|
||||
|
||||
@property (weak, nonatomic) IBOutlet UILabel *createAccountLabel;
|
||||
|
||||
@property (weak, nonatomic) IBOutlet UIView *authInputsContainerView;
|
||||
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *authInputContainerViewHeightConstraint;
|
||||
@property (weak, nonatomic) IBOutlet AuthInputsPasswordBasedView *authInputsPasswordBasedView;
|
||||
@property (weak, nonatomic) IBOutlet AuthInputsEmailCodeBasedView *authInputsEmailCodeBasedView;
|
||||
|
||||
@property (weak, nonatomic) IBOutlet UITextField *homeServerTextField;
|
||||
@property (weak, nonatomic) IBOutlet UILabel *homeServerInfoLabel;
|
||||
@property (weak, nonatomic) IBOutlet UITextField *identityServerTextField;
|
||||
@property (weak, nonatomic) IBOutlet UILabel *identityServerInfoLabel;
|
||||
|
||||
@property (weak, nonatomic) IBOutlet UIButton *submitButton;
|
||||
@property (weak, nonatomic) IBOutlet UIButton *authSwitchButton;
|
||||
|
||||
@property (strong, nonatomic) IBOutlet UIActivityIndicatorView *authenticationActivityIndicator;
|
||||
@property (weak, nonatomic) IBOutlet UILabel *noFlowLabel;
|
||||
@property (weak, nonatomic) IBOutlet UIButton *retryButton;
|
||||
|
||||
@property (weak, nonatomic) IBOutlet UIView *registrationFallbackContentView;
|
||||
@property (weak, nonatomic) IBOutlet MXCRegistrationWebView *registrationFallbackWebView;
|
||||
@property (weak, nonatomic) IBOutlet UIButton *cancelRegistrationFallbackButton;
|
||||
|
||||
@end
|
||||
|
||||
@implementation AuthenticationViewController
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
// Do any additional setup after loading the view, typically from a nib.
|
||||
|
||||
// Force contentView in full width
|
||||
NSLayoutConstraint *leftConstraint = [NSLayoutConstraint constraintWithItem:self.contentView
|
||||
attribute:NSLayoutAttributeLeading
|
||||
relatedBy:0
|
||||
toItem:self.view
|
||||
attribute:NSLayoutAttributeLeft
|
||||
multiplier:1.0
|
||||
constant:0];
|
||||
[self.view addConstraint:leftConstraint];
|
||||
|
||||
NSLayoutConstraint *rightConstraint = [NSLayoutConstraint constraintWithItem:self.contentView
|
||||
attribute:NSLayoutAttributeTrailing
|
||||
relatedBy:0
|
||||
toItem:self.view
|
||||
attribute:NSLayoutAttributeRight
|
||||
multiplier:1.0
|
||||
constant:0];
|
||||
[self.view addConstraint:rightConstraint];
|
||||
|
||||
_authenticationScrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
|
||||
|
||||
_submitButton.enabled = NO;
|
||||
_authSwitchButton.enabled = YES;
|
||||
_authInputsPasswordBasedView.delegate = self;
|
||||
_authInputsEmailCodeBasedView.delegate = self;
|
||||
|
||||
supportedFlows = [NSMutableArray array];
|
||||
|
||||
_homeServerTextField.text = [[MatrixHandler sharedHandler] homeServerURL];
|
||||
_identityServerTextField.text = [[MatrixHandler sharedHandler] identityServerURL];
|
||||
|
||||
// Set rageShake handler
|
||||
// Setup `MXKAuthenticationViewController` properties
|
||||
self.rageShakeManager = [RageShakeManager sharedManager];
|
||||
self.defaultHomeServerUrl = [[NSUserDefaults standardUserDefaults] objectForKey:@"homeserverurl"];
|
||||
self.defaultIdentityServerUrl = [[NSUserDefaults standardUserDefaults] objectForKey:@"identityserverurl"];
|
||||
|
||||
// Set initial auth type
|
||||
_authType = AuthenticationTypeLogin;
|
||||
// The view controller dismiss itself on successful login.
|
||||
self.delegate = self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
supportedFlows = nil;
|
||||
if (mxCurrentOperation){
|
||||
[mxCurrentOperation cancel];
|
||||
mxCurrentOperation = nil;
|
||||
#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"];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)didReceiveMemoryWarning {
|
||||
[super didReceiveMemoryWarning];
|
||||
// Dispose of any resources that can be recreated.
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated {
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
// Update supported authentication flow
|
||||
self.authType = _authType;
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onKeyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onKeyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
|
||||
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onTextFieldChange:) name:UITextFieldTextDidChangeNotification object:nil];
|
||||
}
|
||||
|
||||
- (void)viewWillDisappear:(BOOL)animated {
|
||||
[super viewWillDisappear:animated];
|
||||
|
||||
[self dismissKeyboard];
|
||||
|
||||
// close any opened alert
|
||||
if (alert) {
|
||||
[alert dismiss:NO];
|
||||
alert = nil;
|
||||
if (self.identityServerTextField.text.length) {
|
||||
[[NSUserDefaults standardUserDefaults] setObject:self.identityServerTextField.text forKey:@"identityserverurl"];
|
||||
}
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:AFNetworkingReachabilityDidChangeNotification object:nil];
|
||||
[[NSUserDefaults standardUserDefaults] synchronize];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:UITextFieldTextDidChangeNotification object:nil];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
+ (BOOL)isImplementedFlowType:(NSString*)flowType forAuthType:(AuthenticationType)authType {
|
||||
if (authType == AuthenticationTypeLogin) {
|
||||
if ([flowType isEqualToString:kMXLoginFlowTypePassword]
|
||||
/*|| [flowType isEqualToString:kMXLoginFlowTypeEmailCode]*/) {
|
||||
return YES;
|
||||
}
|
||||
} else { // AuthenticationTypeRegister
|
||||
// No registration flow is supported yet
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)setAuthType:(AuthenticationType)authType {
|
||||
if (authType == AuthenticationTypeLogin) {
|
||||
_createAccountLabel.hidden = YES;
|
||||
[_submitButton setTitle:@"Login" forState:UIControlStateNormal];
|
||||
[_submitButton setTitle:@"Login" forState:UIControlStateHighlighted];
|
||||
[_authSwitchButton setTitle:@"Create account" forState:UIControlStateNormal];
|
||||
[_authSwitchButton setTitle:@"Create account" forState:UIControlStateHighlighted];
|
||||
} else {
|
||||
_createAccountLabel.hidden = NO;
|
||||
[_submitButton setTitle:@"Sign up" forState:UIControlStateNormal];
|
||||
[_submitButton setTitle:@"Sign up" forState:UIControlStateHighlighted];
|
||||
[_authSwitchButton setTitle:@"Back" forState:UIControlStateNormal];
|
||||
[_authSwitchButton setTitle:@"Back" forState:UIControlStateHighlighted];
|
||||
}
|
||||
|
||||
_authType = authType;
|
||||
|
||||
// Update supported authentication flow
|
||||
[self refreshSupportedAuthFlow];
|
||||
}
|
||||
|
||||
- (void)setSelectedFlow:(MXLoginFlow *)selectedFlow {
|
||||
// Hide views which depend on auth flow
|
||||
_submitButton.hidden = YES;
|
||||
_authInputsPasswordBasedView.hidden = YES;
|
||||
_authInputsEmailCodeBasedView.hidden = YES;
|
||||
_noFlowLabel.hidden = YES;
|
||||
_retryButton.hidden = YES;
|
||||
currentAuthInputsView = nil;
|
||||
|
||||
// Select the right auth inputs view
|
||||
if ([selectedFlow.type isEqualToString:kMXLoginFlowTypePassword]) {
|
||||
currentAuthInputsView = _authInputsPasswordBasedView;
|
||||
} else if ([selectedFlow.type isEqualToString:kMXLoginFlowTypeEmailCode]) {
|
||||
currentAuthInputsView = _authInputsEmailCodeBasedView;
|
||||
}
|
||||
|
||||
if (currentAuthInputsView) {
|
||||
_submitButton.hidden = NO;
|
||||
currentAuthInputsView.hidden = NO;
|
||||
currentAuthInputsView.authType = _authType;
|
||||
_authInputContainerViewHeightConstraint.constant = currentAuthInputsView.actualHeight;
|
||||
} else {
|
||||
// No input fields are displayed
|
||||
_authInputContainerViewHeightConstraint.constant = 80;
|
||||
}
|
||||
|
||||
[self.view layoutIfNeeded];
|
||||
|
||||
// Refresh content view height
|
||||
_contentViewHeightConstraint.constant = _authSwitchButton.frame.origin.y + _authSwitchButton.frame.size.height + 15;
|
||||
|
||||
_selectedFlow = selectedFlow;
|
||||
}
|
||||
|
||||
- (void)setUserInteractionEnabled:(BOOL)isEnabled {
|
||||
_submitButton.enabled = (isEnabled && currentAuthInputsView.areAllRequiredFieldsFilled && _homeServerTextField.text.length);
|
||||
_authSwitchButton.enabled = isEnabled;
|
||||
|
||||
_homeServerTextField.enabled = isEnabled;
|
||||
_identityServerTextField.enabled = isEnabled;
|
||||
}
|
||||
|
||||
- (void)refreshSupportedAuthFlow {
|
||||
MatrixHandler *mxHandler = [MatrixHandler sharedHandler];
|
||||
|
||||
// Remove reachability observer
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:AFNetworkingReachabilityDidChangeNotification object:nil];
|
||||
|
||||
// Cancel potential request in progress
|
||||
[mxCurrentOperation cancel];
|
||||
mxCurrentOperation = nil;
|
||||
|
||||
[_authenticationActivityIndicator startAnimating];
|
||||
self.selectedFlow = nil;
|
||||
if (_authType == AuthenticationTypeLogin) {
|
||||
mxCurrentOperation = [mxHandler.mxRestClient getLoginFlow:^(NSArray *flows) {
|
||||
[self handleHomeServerFlows:flows];
|
||||
} failure:^(NSError *error) {
|
||||
NSLog(@"[AuthenticationVC] Failed to get Login flows: %@", error);
|
||||
[self onFailureDuringMXOperation:error];
|
||||
}];
|
||||
} else {
|
||||
// mxCurrentOperation = [mxHandler.mxRestClient getRegisterFlow:^(NSArray *flows) {
|
||||
// [self handleHomeServerFlows:flows];
|
||||
// } failure:^(NSError *error) {
|
||||
// NSLog(@"[AuthenticationVC] Failed to get Register flows: %@", error);
|
||||
// [self onFailureDuringMXOperation:error];
|
||||
// }];
|
||||
|
||||
// Currently no registration flow are supported, we switch directly to the fallback page
|
||||
[self showRegistrationFallBackView:[mxHandler.mxRestClient registerFallback]];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)handleHomeServerFlows:(NSArray *)flows {
|
||||
[_authenticationActivityIndicator stopAnimating];
|
||||
|
||||
[supportedFlows removeAllObjects];
|
||||
for (MXLoginFlow* flow in flows) {
|
||||
if ([AuthenticationViewController isImplementedFlowType:flow.type forAuthType:_authType]) {
|
||||
// Check here all stages
|
||||
BOOL isSupported = YES;
|
||||
if (flow.stages.count) {
|
||||
for (NSString *stage in flow.stages) {
|
||||
if ([AuthenticationViewController isImplementedFlowType:stage forAuthType:_authType] == NO) {
|
||||
isSupported = NO;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isSupported) {
|
||||
[supportedFlows addObject:flow];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (supportedFlows.count) {
|
||||
// FIXME display supported flows
|
||||
// Currently we select the first one
|
||||
self.selectedFlow = [supportedFlows firstObject];
|
||||
}
|
||||
|
||||
if (!_selectedFlow) {
|
||||
// Notify user that no flow is supported
|
||||
if (_authType == AuthenticationTypeLogin) {
|
||||
_noFlowLabel.text = @"Currently we do not support Login flows defined by this Home Server.";
|
||||
} else {
|
||||
_noFlowLabel.text = @"Registration is not currently supported.";
|
||||
}
|
||||
NSLog(@"[AuthenticationVC] Warning: %@", _noFlowLabel.text);
|
||||
|
||||
_noFlowLabel.hidden = NO;
|
||||
_retryButton.hidden = NO;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)onFailureDuringMXOperation:(NSError*)error {
|
||||
mxCurrentOperation = nil;
|
||||
|
||||
if ([error.domain isEqualToString:NSURLErrorDomain] && error.code == kCFURLErrorCancelled) {
|
||||
// Ignore this error
|
||||
return;
|
||||
}
|
||||
|
||||
[_authenticationActivityIndicator stopAnimating];
|
||||
|
||||
// Alert user
|
||||
NSString *title = [error.userInfo valueForKey:NSLocalizedFailureReasonErrorKey];
|
||||
if (!title)
|
||||
{
|
||||
title = @"Error";
|
||||
}
|
||||
NSString *msg = [error.userInfo valueForKey:NSLocalizedDescriptionKey];
|
||||
|
||||
alert = [[MXKAlert alloc] initWithTitle:title message:msg style:MXKAlertStyleAlert];
|
||||
alert.cancelButtonIndex = [alert addActionWithTitle:@"Dismiss" style:MXKAlertActionStyleDefault handler:^(MXKAlert *alert) {}];
|
||||
[alert showInViewController:self];
|
||||
|
||||
// Display failure reason
|
||||
_noFlowLabel.hidden = NO;
|
||||
_noFlowLabel.text = [error.userInfo valueForKey:NSLocalizedDescriptionKey];
|
||||
if (!_noFlowLabel.text.length) {
|
||||
_noFlowLabel.text = @"We failed to retrieve authentication information from this Home Server";
|
||||
}
|
||||
_retryButton.hidden = NO;
|
||||
|
||||
// Handle specific error code here
|
||||
if ([error.domain isEqualToString:NSURLErrorDomain]) {
|
||||
// Check network reachability
|
||||
if (error.code == NSURLErrorNotConnectedToInternet) {
|
||||
// Add reachability observer in order to launch a new request when network will be available
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onReachabilityStatusChange:) name:AFNetworkingReachabilityDidChangeNotification object:nil];
|
||||
} else if (error.code == kCFURLErrorTimedOut) {
|
||||
// Send a new request in 2 sec
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
[self refreshSupportedAuthFlow];
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)onReachabilityStatusChange:(NSNotification *)notif {
|
||||
AFNetworkReachabilityManager *reachabilityManager = [AFNetworkReachabilityManager sharedManager];
|
||||
AFNetworkReachabilityStatus status = reachabilityManager.networkReachabilityStatus;
|
||||
|
||||
if (status == AFNetworkReachabilityStatusReachableViaWiFi || status == AFNetworkReachabilityStatusReachableViaWWAN) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self refreshSupportedAuthFlow];
|
||||
});
|
||||
} else if (status == AFNetworkReachabilityStatusNotReachable) {
|
||||
_noFlowLabel.text = @"Please check your network connectivity";
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)onButtonPressed:(id)sender {
|
||||
[self dismissKeyboard];
|
||||
|
||||
if (sender == _submitButton) {
|
||||
MatrixHandler *matrix = [MatrixHandler sharedHandler];
|
||||
if (matrix.mxRestClient) {
|
||||
// Disable user interaction to prevent multiple requests
|
||||
[self setUserInteractionEnabled:NO];
|
||||
[_authenticationActivityIndicator startAnimating];
|
||||
|
||||
if (_authType == AuthenticationTypeLogin) {
|
||||
if ([_selectedFlow.type isEqualToString:kMXLoginFlowTypePassword]) {
|
||||
[matrix.mxRestClient loginWithUser:matrix.userLogin andPassword:_authInputsPasswordBasedView.passWordTextField.text
|
||||
success:^(MXCredentials *credentials){
|
||||
[_authenticationActivityIndicator stopAnimating];
|
||||
|
||||
// Report credentials
|
||||
[matrix setUserId:credentials.userId];
|
||||
[matrix setAccessToken:credentials.accessToken];
|
||||
// Extract homeServer name from userId
|
||||
NSArray *components = [credentials.userId componentsSeparatedByString:@":"];
|
||||
if (components.count == 2) {
|
||||
[matrix setHomeServer:[components lastObject]];
|
||||
} else {
|
||||
NSLog(@"[AuthenticationVC] Warning: the userId is not correctly formatted: %@", credentials.userId);
|
||||
}
|
||||
|
||||
[self dismissViewControllerAnimated:YES completion:nil];
|
||||
}
|
||||
failure:^(NSError *error){
|
||||
[self onFailureDuringAuthRequest:error];
|
||||
}];
|
||||
} else {
|
||||
// FIXME
|
||||
[self onFailureDuringAuthRequest:[NSError errorWithDomain:nil code:0 userInfo:@{@"error": @"Not supported yet"}]];
|
||||
}
|
||||
} else {
|
||||
// FIXME
|
||||
[self onFailureDuringAuthRequest:[NSError errorWithDomain:nil code:0 userInfo:@{@"error": @"Not supported yet"}]];
|
||||
}
|
||||
}
|
||||
} else if (sender == _authSwitchButton){
|
||||
if (_authType == AuthenticationTypeLogin) {
|
||||
self.authType = AuthenticationTypeRegister;
|
||||
} else {
|
||||
self.authType = AuthenticationTypeLogin;
|
||||
}
|
||||
} else if (sender == _retryButton) {
|
||||
[self refreshSupportedAuthFlow];
|
||||
} else if (sender == _cancelRegistrationFallbackButton) {
|
||||
// Hide fallback webview
|
||||
[self hideRegistrationFallbackView];
|
||||
self.authType = AuthenticationTypeLogin;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)onFailureDuringAuthRequest:(NSError *)error {
|
||||
[_authenticationActivityIndicator stopAnimating];
|
||||
[self setUserInteractionEnabled:YES];
|
||||
|
||||
NSLog(@"[AuthenticationVC] Auth request failed: %@", error);
|
||||
|
||||
// translate the error code to a human message
|
||||
NSString* message = error.localizedDescription;
|
||||
NSDictionary* dict = error.userInfo;
|
||||
|
||||
// detect if it is a Matrix SDK issue
|
||||
if (dict) {
|
||||
NSString* localizedError = [dict valueForKey:@"error"];
|
||||
NSString* errCode = [dict valueForKey:@"errcode"];
|
||||
|
||||
if (errCode) {
|
||||
if ([errCode isEqualToString:@"M_FORBIDDEN"]) {
|
||||
message = @"Invalid username/password";
|
||||
} else if (localizedError.length > 0) {
|
||||
message = localizedError;
|
||||
} else if ([errCode isEqualToString:@"M_UNKNOWN_TOKEN"]) {
|
||||
message = @"The access token specified was not recognised";
|
||||
} else if ([errCode isEqualToString:@"M_BAD_JSON"]) {
|
||||
message = @"Malformed JSON";
|
||||
} else if ([errCode isEqualToString:@"M_NOT_JSON"]) {
|
||||
message = @"Did not contain valid JSON";
|
||||
} else if ([errCode isEqualToString:@"M_LIMIT_EXCEEDED"]) {
|
||||
message = @"Too many requests have been sent";
|
||||
} else if ([errCode isEqualToString:@"M_USER_IN_USE"]) {
|
||||
message = @"This user name is already used";
|
||||
} else if ([errCode isEqualToString:@"M_LOGIN_EMAIL_URL_NOT_YET"]) {
|
||||
message = @"The email link which has not been clicked yet";
|
||||
} else {
|
||||
message = errCode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Alert user
|
||||
alert = [[MXKAlert alloc] initWithTitle:@"Login Failed" message:message style:MXKAlertStyleAlert];
|
||||
[alert addActionWithTitle:@"Dismiss" style:MXKAlertActionStyleCancel handler:^(MXKAlert *alert) {}];
|
||||
[alert showInViewController:self];
|
||||
}
|
||||
|
||||
#pragma mark - Keyboard handling
|
||||
|
||||
- (void)onKeyboardWillShow:(NSNotification *)notif {
|
||||
NSValue *rectVal = notif.userInfo[UIKeyboardFrameEndUserInfoKey];
|
||||
CGRect endRect = rectVal.CGRectValue;
|
||||
|
||||
UIEdgeInsets insets = self.authenticationScrollView.contentInset;
|
||||
// Handle portrait/landscape mode
|
||||
insets.bottom = (endRect.origin.y == 0) ? endRect.size.width : endRect.size.height;
|
||||
self.authenticationScrollView.contentInset = insets;
|
||||
}
|
||||
|
||||
- (void)onKeyboardWillHide:(NSNotification *)notif {
|
||||
UIEdgeInsets insets = self.authenticationScrollView.contentInset;
|
||||
insets.bottom = 0;
|
||||
self.authenticationScrollView.contentInset = insets;
|
||||
}
|
||||
|
||||
- (void)dismissKeyboard {
|
||||
// Hide the keyboard
|
||||
[currentAuthInputsView dismissKeyboard];
|
||||
[_homeServerTextField resignFirstResponder];
|
||||
[_identityServerTextField resignFirstResponder];
|
||||
}
|
||||
|
||||
#pragma mark - UITextField delegate
|
||||
|
||||
- (void)onTextFieldChange:(NSNotification *)notif {
|
||||
NSString *homeServerURL = _homeServerTextField.text;
|
||||
|
||||
if (currentAuthInputsView.areAllRequiredFieldsFilled && homeServerURL.length) {
|
||||
_submitButton.enabled = YES;
|
||||
} else {
|
||||
_submitButton.enabled = NO;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)textFieldDidEndEditing:(UITextField *)textField {
|
||||
MatrixHandler *mxHandler = [MatrixHandler sharedHandler];
|
||||
if (textField == _homeServerTextField) {
|
||||
if (![[mxHandler homeServerURL] isEqualToString:textField.text]) {
|
||||
[mxHandler setHomeServerURL:textField.text];
|
||||
if (!textField.text.length) {
|
||||
// Force refresh with default value
|
||||
textField.text = [mxHandler homeServerURL];
|
||||
}
|
||||
// Refresh UI
|
||||
[self refreshSupportedAuthFlow];
|
||||
}
|
||||
}
|
||||
else if (textField == _identityServerTextField) {
|
||||
[mxHandler setIdentityServerURL:textField.text];
|
||||
if (!textField.text.length) {
|
||||
// Force refresh with default value
|
||||
textField.text = [mxHandler identityServerURL];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)textFieldShouldReturn:(UITextField*)textField {
|
||||
if (textField.returnKeyType == UIReturnKeyDone) {
|
||||
// "Done" key has been pressed
|
||||
[textField resignFirstResponder];
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
#pragma mark - AuthInputsViewDelegate delegate
|
||||
|
||||
- (void)authInputsDoneKeyHasBeenPressed:(AuthInputsView *)authInputsView {
|
||||
if (_submitButton.isEnabled) {
|
||||
// Launch authentication now
|
||||
[self onButtonPressed:_submitButton];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Registration Fallback
|
||||
|
||||
- (void)showRegistrationFallBackView:(NSString*)fallbackPage {
|
||||
_authenticationScrollView.hidden = YES;
|
||||
_registrationFallbackContentView.hidden = NO;
|
||||
|
||||
[_registrationFallbackWebView openFallbackPage:fallbackPage success:^(MXCredentials *credentials) {
|
||||
// Report credentials
|
||||
MatrixHandler *mxHandler = [MatrixHandler sharedHandler];
|
||||
[mxHandler setUserId:credentials.userId];
|
||||
[mxHandler setAccessToken:credentials.accessToken];
|
||||
// Extract homeServer name from userId
|
||||
NSArray *components = [credentials.userId componentsSeparatedByString:@":"];
|
||||
if (components.count == 2) {
|
||||
[mxHandler setHomeServer:[components lastObject]];
|
||||
} else {
|
||||
NSLog(@"[AuthenticationVC] Warning: the userId is not correctly formatted: %@", credentials.userId);
|
||||
}
|
||||
|
||||
[self dismissViewControllerAnimated:YES completion:nil];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)hideRegistrationFallbackView {
|
||||
[_registrationFallbackWebView stopLoading];
|
||||
_authenticationScrollView.hidden = NO;
|
||||
_registrationFallbackContentView.hidden = YES;
|
||||
// Dismiss on successful login
|
||||
[self dismissViewControllerAnimated:YES completion:nil];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -108,7 +108,7 @@
|
|||
[super viewDidAppear:animated];
|
||||
|
||||
// Check whether we're not logged in
|
||||
if (![MatrixHandler sharedHandler].accessToken) {
|
||||
if (![MXKAccountManager sharedManager].accounts.count) {
|
||||
[self showAuthenticationScreen];
|
||||
}
|
||||
}
|
||||
|
@ -215,7 +215,16 @@
|
|||
}
|
||||
|
||||
- (void)setVisibleRoomId:(NSString *)aVisibleRoomId {
|
||||
[[MatrixHandler sharedHandler] restoreInAppNotificationsForRoomId:aVisibleRoomId];
|
||||
|
||||
// Presently only the first account is used
|
||||
// TODO GFO: handle multi-session
|
||||
MXKAccount *account = [[MXKAccountManager sharedManager].accounts firstObject];
|
||||
if (account) {
|
||||
// Enable inApp notification for this room
|
||||
[account updateNotificationListenerForRoomId:aVisibleRoomId ignore:NO];
|
||||
}
|
||||
|
||||
|
||||
_visibleRoomId = aVisibleRoomId;
|
||||
}
|
||||
|
||||
|
|
|
@ -230,7 +230,7 @@
|
|||
if (textField == _roomTitleView.displayNameTextField) {
|
||||
// Check whether the user has enough power to rename the room
|
||||
MXRoomPowerLevels *powerLevels = [self.roomDataSource.room.state powerLevels];
|
||||
NSUInteger userPowerLevel = [powerLevels powerLevelOfUserWithUserID:[MatrixHandler sharedHandler].userId];
|
||||
NSUInteger userPowerLevel = [powerLevels powerLevelOfUserWithUserID:self.mxSession.myUser.userId];
|
||||
if (userPowerLevel >= [powerLevels minimumPowerLevelForSendingEventAsStateEvent:kMXEventTypeStringRoomName]) {
|
||||
// Only the room name is edited here, update the text field with the room name
|
||||
textField.text = self.roomDataSource.room.state.name;
|
||||
|
@ -253,7 +253,7 @@
|
|||
} else if (textField == _roomTitleView.topicTextField) {
|
||||
// Check whether the user has enough power to edit room topic
|
||||
MXRoomPowerLevels *powerLevels = [self.roomDataSource.room.state powerLevels];
|
||||
NSUInteger userPowerLevel = [powerLevels powerLevelOfUserWithUserID:[MatrixHandler sharedHandler].userId];
|
||||
NSUInteger userPowerLevel = [powerLevels powerLevelOfUserWithUserID:self.mxSession.myUser.userId];
|
||||
if (userPowerLevel >= [powerLevels minimumPowerLevelForSendingEventAsStateEvent:kMXEventTypeStringRoomTopic]) {
|
||||
textField.backgroundColor = [UIColor whiteColor];
|
||||
[self.roomTitleView stopTopicAnimation];
|
||||
|
|
|
@ -1057,7 +1057,7 @@ NSString* const kCommandsDescriptionText = @"The following commands are availabl
|
|||
// tap on clear application cache
|
||||
if ((indexPath.section == SETTINGS_SECTION_ROOMS_INDEX) && (indexPath.row == SETTINGS_SECTION_ROOMS_CLEAR_CACHE_INDEX)) {
|
||||
// clear caches
|
||||
[[MatrixHandler sharedHandler] reload:YES];
|
||||
[[AppDelegate theDelegate] reloadMatrixSessions:YES];
|
||||
}
|
||||
else if (indexPath.section == SETTINGS_SECTION_CONTACTS_INDEX) {
|
||||
|
||||
|
|
Loading…
Reference in a new issue