mirror of
https://github.com/firebase/firebase-ios-sdk
synced 2026-11-09 22:36:01 +05:45
582 lines
22 KiB
Objective-C
582 lines
22 KiB
Objective-C
/*
|
|
* Copyright 2019 Google
|
|
*
|
|
* 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 "MainViewController.h"
|
|
#import "MainViewController+App.h"
|
|
#import "MainViewController+Auth.h"
|
|
#import "MainViewController+AutoTests.h"
|
|
#import "MainViewController+Custom.h"
|
|
#import "MainViewController+Email.h"
|
|
#import "MainViewController+Facebook.h"
|
|
#import "MainViewController+GameCenter.h"
|
|
#import "MainViewController+Google.h"
|
|
#import "MainViewController+Internal.h"
|
|
#import "MainViewController+OAuth.h"
|
|
#import "MainViewController+OOB.h"
|
|
#import "MainViewController+Phone.h"
|
|
#import "MainViewController+User.h"
|
|
|
|
#import <objc/runtime.h>
|
|
|
|
#import <FirebaseCore/FIRApp.h>
|
|
#import <FirebaseCore/FIRAppInternal.h>
|
|
|
|
#import "AppManager.h"
|
|
#import "AuthCredentials.h"
|
|
#import "FIRAdditionalUserInfo.h"
|
|
#import "FIROAuthProvider.h"
|
|
#import "FIRPhoneAuthCredential.h"
|
|
#import "FIRPhoneAuthProvider.h"
|
|
#import "FIRAuthTokenResult.h"
|
|
#import "FirebaseAuth.h"
|
|
#import "FacebookAuthProvider.h"
|
|
#import "GoogleAuthProvider.h"
|
|
#import "SettingsViewController.h"
|
|
#import "StaticContentTableViewManager.h"
|
|
#import "UIViewController+Alerts.h"
|
|
#import "UserInfoViewController.h"
|
|
#import "UserTableViewCell.h"
|
|
#import "FIRAuth_Internal.h"
|
|
|
|
NS_ASSUME_NONNULL_BEGIN
|
|
|
|
static NSString *const kSectionTitleSettings = @"Settings";
|
|
|
|
static NSString *const kSectionTitleUserDetails = @"User Defaults";
|
|
|
|
static NSString *const kSwitchToInMemoryUserTitle = @"Switch to in memory user";
|
|
|
|
static NSString *const kNewOrExistingUserToggleTitle = @"New or Existing User Toggle";
|
|
|
|
typedef void (^FIRTokenCallback)(NSString *_Nullable token, NSError *_Nullable error);
|
|
|
|
@implementation MainViewController {
|
|
NSMutableString *_consoleString;
|
|
|
|
/** @var _userInMemory
|
|
@brief Acts like the "memory" function of a calculator. An operation allows sample app users
|
|
to assign this value based on @c FIRAuth.currentUser or clear this value.
|
|
*/
|
|
FIRUser *_userInMemory;
|
|
|
|
/** @var _useUserInMemory
|
|
@brief Instructs the application to use _userInMemory instead of @c FIRAuth.currentUser for
|
|
testing operations. This allows us to test if things still work with a user who is not
|
|
the @c FIRAuth.currentUser, and also allows us to test those things while
|
|
@c FIRAuth.currentUser remains nil (after a sign-out) and also when @c FIRAuth.currentUser
|
|
is non-nil (do to a subsequent sign-in.)
|
|
*/
|
|
BOOL _useUserInMemory;
|
|
}
|
|
|
|
- (id)initWithNibName:(nullable NSString *)nibNameOrNil bundle:(nullable NSBundle *)nibBundleOrNil {
|
|
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
|
|
if (self) {
|
|
_actionCodeRequestType = ActionCodeRequestTypeInApp;
|
|
_actionCodeContinueURL = [NSURL URLWithString:KCONTINUE_URL];
|
|
_authStateDidChangeListeners = [NSMutableArray array];
|
|
_IDTokenDidChangeListeners = [NSMutableArray array];
|
|
_googleOAuthProvider = [FIROAuthProvider providerWithProviderID:FIRGoogleAuthProviderID];
|
|
_microsoftOAuthProvider = [FIROAuthProvider providerWithProviderID:@"microsoft.com"];
|
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
selector:@selector(authStateChangedForAuth:)
|
|
name:FIRAuthStateDidChangeNotification
|
|
object:nil];
|
|
self.useStatusBarSpinner = YES;
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (void)viewDidLoad {
|
|
[super viewDidLoad];
|
|
|
|
// Give us a circle for the image view:
|
|
_userInfoTableViewCell.userInfoProfileURLImageView.layer.cornerRadius =
|
|
_userInfoTableViewCell.userInfoProfileURLImageView.frame.size.width / 2.0f;
|
|
_userInfoTableViewCell.userInfoProfileURLImageView.layer.masksToBounds = YES;
|
|
_userInMemoryInfoTableViewCell.userInfoProfileURLImageView.layer.cornerRadius =
|
|
_userInMemoryInfoTableViewCell.userInfoProfileURLImageView.frame.size.width / 2.0f;
|
|
_userInMemoryInfoTableViewCell.userInfoProfileURLImageView.layer.masksToBounds = YES;
|
|
}
|
|
|
|
- (void)viewWillAppear:(BOOL)animated {
|
|
[super viewWillAppear:animated];
|
|
[self updateTable];
|
|
[self updateUserInfo];
|
|
}
|
|
|
|
#pragma mark - Public
|
|
|
|
- (BOOL)handleIncomingLinkWithURL:(NSURL *)URL {
|
|
// Parse the query portion of the incoming URL.
|
|
NSDictionary<NSString *, NSString *> *queryItems =
|
|
parseURL([NSURLComponents componentsWithString:URL.absoluteString].query);
|
|
|
|
// Check that all necessary query items are available.
|
|
NSString *actionCode = queryItems[@"oobCode"];
|
|
NSString *mode = queryItems[@"mode"];
|
|
if (!actionCode || !mode) {
|
|
return NO;
|
|
}
|
|
// Handle Password Reset action.
|
|
if ([mode isEqualToString:kPasswordResetAction]) {
|
|
[self showTextInputPromptWithMessage:@"New Password:"
|
|
completionBlock:^(BOOL userPressedOK, NSString *_Nullable newPassword) {
|
|
if (!userPressedOK || !newPassword.length) {
|
|
[UIPasteboard generalPasteboard].string = actionCode;
|
|
return;
|
|
}
|
|
[self showSpinner:^() {
|
|
[[AppManager auth] confirmPasswordResetWithCode:actionCode
|
|
newPassword:newPassword
|
|
completion:^(NSError *_Nullable error) {
|
|
[self hideSpinner:^{
|
|
if (error) {
|
|
[self logFailure:@"Password reset in app failed" error:error];
|
|
[self showMessagePrompt:error.localizedDescription];
|
|
return;
|
|
}
|
|
[self logSuccess:@"Password reset in app succeeded."];
|
|
[self showMessagePrompt:@"Password reset in app succeeded."];
|
|
}];
|
|
}];
|
|
}];
|
|
}];
|
|
return YES;
|
|
}
|
|
if ([mode isEqualToString:kVerifyEmailAction]) {
|
|
[self showMessagePromptWithTitle:@"Tap OK to verify email"
|
|
message:actionCode
|
|
showCancelButton:YES
|
|
completion:^(BOOL userPressedOK, NSString *_Nullable userInput) {
|
|
if (!userPressedOK) {
|
|
return;
|
|
}
|
|
[self showSpinner:^() {
|
|
[[AppManager auth] applyActionCode:actionCode completion:^(NSError *_Nullable error) {
|
|
[self hideSpinner:^{
|
|
if (error) {
|
|
[self logFailure:@"Verify email in app failed" error:error];
|
|
[self showMessagePrompt:error.localizedDescription];
|
|
return;
|
|
}
|
|
[self logSuccess:@"Verify email in app succeeded."];
|
|
[self showMessagePrompt:@"Verify email in app succeeded."];
|
|
}];
|
|
}];
|
|
}];
|
|
}];
|
|
return YES;
|
|
}
|
|
return NO;
|
|
}
|
|
|
|
static NSDictionary<NSString *, NSString *> *parseURL(NSString *urlString) {
|
|
NSString *linkURL = [NSURLComponents componentsWithString:urlString].query;
|
|
NSArray<NSString *> *URLComponents = [linkURL componentsSeparatedByString:@"&"];
|
|
NSMutableDictionary<NSString *, NSString *> *queryItems =
|
|
[[NSMutableDictionary alloc] initWithCapacity:URLComponents.count];
|
|
for (NSString *component in URLComponents) {
|
|
NSRange equalRange = [component rangeOfString:@"="];
|
|
if (equalRange.location != NSNotFound) {
|
|
NSString *queryItemKey =
|
|
[[component substringToIndex:equalRange.location] stringByRemovingPercentEncoding];
|
|
NSString *queryItemValue =
|
|
[[component substringFromIndex:equalRange.location + 1] stringByRemovingPercentEncoding];
|
|
if (queryItemKey && queryItemValue) {
|
|
queryItems[queryItemKey] = queryItemValue;
|
|
}
|
|
}
|
|
}
|
|
return queryItems;
|
|
}
|
|
|
|
- (void)updateTable {
|
|
__weak typeof(self) weakSelf = self;
|
|
_tableViewManager.contents =
|
|
[StaticContentTableViewContent contentWithSections:@[
|
|
// User Defaults
|
|
[StaticContentTableViewSection sectionWithTitle:kSectionTitleUserDetails cells:@[
|
|
[StaticContentTableViewCell cellWithCustomCell:_userInfoTableViewCell action:^{
|
|
[weakSelf presentUserInfo];
|
|
}],
|
|
[StaticContentTableViewCell cellWithCustomCell:_userToUseCell],
|
|
[StaticContentTableViewCell cellWithCustomCell:_userInMemoryInfoTableViewCell action:^{
|
|
[weakSelf presentUserInMemoryInfo];
|
|
}],
|
|
]],
|
|
// Settings
|
|
[StaticContentTableViewSection sectionWithTitle:kSectionTitleSettings cells:@[
|
|
[StaticContentTableViewCell cellWithTitle:kSectionTitleSettings
|
|
action:^{ [weakSelf presentSettings]; }],
|
|
[StaticContentTableViewCell cellWithTitle:kNewOrExistingUserToggleTitle
|
|
value:_isNewUserToggleOn ? @"Enabled" : @"Disabled"
|
|
action:^{
|
|
_isNewUserToggleOn = !_isNewUserToggleOn;
|
|
[self updateTable]; }],
|
|
[StaticContentTableViewCell cellWithTitle:kSwitchToInMemoryUserTitle
|
|
action:^{ [weakSelf updateToSavedUser]; }],
|
|
]],
|
|
// Auth
|
|
[weakSelf authSection],
|
|
// Email Auth
|
|
[weakSelf emailAuthSection],
|
|
// Phone Auth
|
|
[weakSelf phoneAuthSection],
|
|
// Google Auth
|
|
[weakSelf googleAuthSection],
|
|
// Facebook Auth
|
|
[weakSelf facebookAuthSection],
|
|
// OAuth
|
|
[weakSelf oAuthSection],
|
|
// Custom Auth
|
|
[weakSelf customAuthSection],
|
|
// Game Center Auth
|
|
[weakSelf gameCenterAuthSection],
|
|
// User
|
|
[weakSelf userSection],
|
|
// App
|
|
[weakSelf appSection],
|
|
// OOB
|
|
[weakSelf oobSection],
|
|
// Auto Tests
|
|
[weakSelf autoTestsSection],
|
|
]];
|
|
}
|
|
|
|
#pragma mark - Internal
|
|
|
|
- (FIRUser *)user {
|
|
return _useUserInMemory ? _userInMemory : [AppManager auth].currentUser;
|
|
}
|
|
|
|
- (void)signInWithProvider:(nonnull id<AuthProvider>)provider callback:(void(^)(void))callback {
|
|
if (!provider) {
|
|
[self logFailedTest:@"A valid auth provider was not provided to the signInWithProvider."];
|
|
return;
|
|
}
|
|
[provider getAuthCredentialWithPresentingViewController:self
|
|
callback:^(FIRAuthCredential *credential,
|
|
NSError *error) {
|
|
if (!credential) {
|
|
[self logFailedTest:@"The test needs a valid credential to continue."];
|
|
return;
|
|
}
|
|
[[AppManager auth] signInWithCredential:credential
|
|
completion:^(FIRAuthDataResult *_Nullable result,
|
|
NSError *_Nullable error) {
|
|
if (error) {
|
|
[self logFailure:@"sign-in with provider failed" error:error];
|
|
[self logFailedTest:@"Sign-in should succeed"];
|
|
return;
|
|
} else {
|
|
[self logSuccess:@"sign-in with provider succeeded."];
|
|
callback();
|
|
}
|
|
}];
|
|
}];
|
|
}
|
|
|
|
- (FIRActionCodeSettings *)actionCodeSettings {
|
|
FIRActionCodeSettings *actionCodeSettings = [[FIRActionCodeSettings alloc] init];
|
|
actionCodeSettings.URL = self.actionCodeContinueURL;
|
|
actionCodeSettings.handleCodeInApp = self.actionCodeRequestType == ActionCodeRequestTypeInApp;
|
|
return actionCodeSettings;
|
|
}
|
|
|
|
- (void)reauthenticate:(id<AuthProvider>)authProvider retrieveData:(BOOL)retrieveData {
|
|
FIRUser *user = [self user];
|
|
if (!user) {
|
|
NSString *provider = @"Firebase";
|
|
if ([authProvider isKindOfClass:[GoogleAuthProvider class]]) {
|
|
provider = @"Google";
|
|
} else if ([authProvider isKindOfClass:[FacebookAuthProvider class]]) {
|
|
provider = @"Facebook";
|
|
}
|
|
NSString *title = @"Missing User";
|
|
NSString *message =
|
|
[NSString stringWithFormat:@"There is no signed-in %@ user.", provider];
|
|
[self showMessagePromptWithTitle:title message:message showCancelButton:NO completion:nil];
|
|
return;
|
|
}
|
|
[authProvider getAuthCredentialWithPresentingViewController:self
|
|
callback:^(FIRAuthCredential *credential,
|
|
NSError *error) {
|
|
if (credential) {
|
|
FIRAuthDataResultCallback completion = ^(FIRAuthDataResult *_Nullable authResult,
|
|
NSError *_Nullable error) {
|
|
if (error) {
|
|
[self logFailure:@"reauthenticate operation failed" error:error];
|
|
} else {
|
|
[self logSuccess:@"reauthenticate operation succeeded."];
|
|
}
|
|
if (authResult.additionalUserInfo) {
|
|
[self logSuccess:[self stringWithAdditionalUserInfo:authResult.additionalUserInfo]];
|
|
}
|
|
[self showTypicalUIForUserUpdateResultsWithTitle:@"Reauthenticate" error:error];
|
|
};
|
|
[user reauthenticateWithCredential:credential completion:completion];
|
|
}
|
|
}];
|
|
}
|
|
|
|
- (void)signinWithProvider:(id<AuthProvider>)authProvider retrieveData:(BOOL)retrieveData {
|
|
FIRAuth *auth = [AppManager auth];
|
|
if (!auth) {
|
|
return;
|
|
}
|
|
[authProvider getAuthCredentialWithPresentingViewController:self
|
|
callback:^(FIRAuthCredential *credential,
|
|
NSError *error) {
|
|
if (credential) {
|
|
FIRAuthDataResultCallback completion = ^(FIRAuthDataResult *_Nullable authResult,
|
|
NSError *_Nullable error) {
|
|
if (error) {
|
|
[self logFailure:@"sign-in with provider failed" error:error];
|
|
} else {
|
|
[self logSuccess:@"sign-in with provider succeeded."];
|
|
}
|
|
if (authResult.additionalUserInfo) {
|
|
[self logSuccess:[self stringWithAdditionalUserInfo:authResult.additionalUserInfo]];
|
|
if (_isNewUserToggleOn) {
|
|
NSString *newUserString = authResult.additionalUserInfo.isNewUser ?
|
|
@"New user" : @"Existing user";
|
|
[self showMessagePromptWithTitle:@"New or Existing"
|
|
message:newUserString
|
|
showCancelButton:NO
|
|
completion:nil];
|
|
}
|
|
}
|
|
[self showTypicalUIForUserUpdateResultsWithTitle:@"Sign-In" error:error];
|
|
};
|
|
[auth signInWithCredential:credential completion:completion];
|
|
}
|
|
}];
|
|
}
|
|
|
|
- (void)linkWithAuthProvider:(id<AuthProvider>)authProvider retrieveData:(BOOL)retrieveData {
|
|
FIRUser *user = [self user];
|
|
if (!user) {
|
|
return;
|
|
}
|
|
[authProvider getAuthCredentialWithPresentingViewController:self
|
|
callback:^(FIRAuthCredential *credential,
|
|
NSError *error) {
|
|
if (credential) {
|
|
FIRAuthDataResultCallback completion = ^(FIRAuthDataResult *_Nullable authResult,
|
|
NSError *_Nullable error) {
|
|
if (error) {
|
|
[self logFailure:@"link auth provider failed" error:error];
|
|
} else {
|
|
[self logSuccess:@"link auth provider succeeded."];
|
|
}
|
|
if (authResult.additionalUserInfo) {
|
|
[self logSuccess:[self stringWithAdditionalUserInfo:authResult.additionalUserInfo]];
|
|
}
|
|
if (retrieveData) {
|
|
[self showUIForAuthDataResultWithResult:authResult error:error];
|
|
} else {
|
|
[self showTypicalUIForUserUpdateResultsWithTitle:@"Link Account" error:error];
|
|
}
|
|
};
|
|
[user linkWithCredential:credential completion:completion];
|
|
}
|
|
}];
|
|
}
|
|
|
|
- (void)unlinkFromProvider:(NSString *)provider
|
|
completion:(nullable TestAutomationCallback)completion {
|
|
[[self user] unlinkFromProvider:provider
|
|
completion:^(FIRUser *_Nullable user,
|
|
NSError *_Nullable error) {
|
|
if (error) {
|
|
[self logFailure:@"unlink auth provider failed" error:error];
|
|
if (completion) {
|
|
completion(error);
|
|
}
|
|
return;
|
|
}
|
|
[self logSuccess:@"unlink auth provider succeeded."];
|
|
if (completion) {
|
|
completion(nil);
|
|
}
|
|
[self showTypicalUIForUserUpdateResultsWithTitle:@"Unlink from Provider" error:error];
|
|
}];
|
|
}
|
|
|
|
- (void)updateToSavedUser {
|
|
if(![AppManager auth].currentUser) {
|
|
NSLog(@"You must be signed in to perform this action");
|
|
return;
|
|
}
|
|
|
|
if (!_userInMemory) {
|
|
[self showMessagePrompt:[NSString stringWithFormat:@"You need an in-memory user to perform this"
|
|
"action, use the M+ button to save a user to memory.", nil]];
|
|
return;
|
|
}
|
|
|
|
[[AppManager auth] updateCurrentUser:_userInMemory completion:^(NSError *_Nullable error) {
|
|
if (error) {
|
|
[self showMessagePrompt:
|
|
[NSString stringWithFormat:@"An error Occurred: %@", error.localizedDescription]];
|
|
return;
|
|
}
|
|
}];
|
|
}
|
|
|
|
#pragma mark - Private
|
|
|
|
- (void)presentSettings {
|
|
SettingsViewController *settingsViewController = [[SettingsViewController alloc]
|
|
initWithNibName:NSStringFromClass([SettingsViewController class])
|
|
bundle:nil];
|
|
[self showViewController:settingsViewController sender:self];
|
|
}
|
|
|
|
- (void)presentUserInfo {
|
|
UserInfoViewController *userInfoViewController =
|
|
[[UserInfoViewController alloc] initWithUser:[AppManager auth].currentUser];
|
|
[self showViewController:userInfoViewController sender:self];
|
|
}
|
|
|
|
- (void)presentUserInMemoryInfo {
|
|
UserInfoViewController *userInfoViewController =
|
|
[[UserInfoViewController alloc] initWithUser:_userInMemory];
|
|
[self showViewController:userInfoViewController sender:self];
|
|
}
|
|
|
|
- (NSString *)stringWithAdditionalUserInfo:(nullable FIRAdditionalUserInfo *)additionalUserInfo {
|
|
if (!additionalUserInfo) {
|
|
return @"(no additional user info)";
|
|
}
|
|
NSString *newUserString = additionalUserInfo.isNewUser ? @"new user" : @"existing user";
|
|
return [NSString stringWithFormat:@"%@: %@", newUserString, additionalUserInfo.profile];
|
|
}
|
|
|
|
- (void)showTypicalUIForUserUpdateResultsWithTitle:(NSString *)resultsTitle
|
|
error:(NSError * _Nullable)error {
|
|
if (error) {
|
|
NSString *message = [NSString stringWithFormat:@"%@ (%ld)\n%@",
|
|
error.domain,
|
|
(long)error.code,
|
|
error.localizedDescription];
|
|
if (error.code == FIRAuthErrorCodeAccountExistsWithDifferentCredential) {
|
|
NSString *errorEmail = error.userInfo[FIRAuthErrorUserInfoEmailKey];
|
|
resultsTitle = [NSString stringWithFormat:@"Existing email : %@", errorEmail];
|
|
}
|
|
[self showMessagePromptWithTitle:resultsTitle
|
|
message:message
|
|
showCancelButton:NO
|
|
completion:nil];
|
|
return;
|
|
}
|
|
[self updateUserInfo];
|
|
}
|
|
|
|
- (void)showUIForAuthDataResultWithResult:(FIRAuthDataResult *)result
|
|
error:(NSError * _Nullable)error {
|
|
NSString *errorMessage = [NSString stringWithFormat:@"%@ (%ld)\n%@",
|
|
error.domain ?: @"",
|
|
(long)error.code,
|
|
error.localizedDescription ?: @""];
|
|
[self showMessagePromptWithTitle:@"Error"
|
|
message:errorMessage
|
|
showCancelButton:NO
|
|
completion:^(BOOL userPressedOK,
|
|
NSString *_Nullable userInput) {
|
|
[self showMessagePromptWithTitle:@"Profile Info"
|
|
message:[self stringWithAdditionalUserInfo:result.additionalUserInfo]
|
|
showCancelButton:NO
|
|
completion:nil];
|
|
[self updateUserInfo];
|
|
}];
|
|
}
|
|
|
|
- (void)updateUserInfo {
|
|
[_userInfoTableViewCell updateContentsWithUser:[AppManager auth].currentUser];
|
|
[_userInMemoryInfoTableViewCell updateContentsWithUser:_userInMemory];
|
|
}
|
|
|
|
- (void)authStateChangedForAuth:(NSNotification *)notification {
|
|
[self updateUserInfo];
|
|
if (notification) {
|
|
[self log:[NSString stringWithFormat:
|
|
@"received FIRAuthStateDidChange notification on user '%@'.",
|
|
((FIRAuth *)notification.object).currentUser.uid]];
|
|
}
|
|
}
|
|
|
|
- (void)log:(NSString *)string {
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
|
|
dateFormatter.dateFormat = @"yyyy-MM-dd HH:mm:ss";
|
|
NSString *date = [dateFormatter stringFromDate:[NSDate date]];
|
|
if (!_consoleString) {
|
|
_consoleString = [NSMutableString string];
|
|
}
|
|
[_consoleString appendString:[NSString stringWithFormat:@"%@ %@\n", date, string]];
|
|
_consoleTextView.text = _consoleString;
|
|
|
|
CGRect targetRect = CGRectMake(0, _consoleTextView.contentSize.height - 1, 1, 1);
|
|
[_consoleTextView scrollRectToVisible:targetRect animated:YES];
|
|
});
|
|
}
|
|
|
|
- (void)logSuccess:(NSString *)string {
|
|
[self log:[NSString stringWithFormat:@"SUCCESS: %@", string]];
|
|
}
|
|
|
|
- (void)logFailure:(NSString *)string error:(NSError * _Nullable) error {
|
|
NSString *message =
|
|
[NSString stringWithFormat:@"FAILURE: %@ Error Description: %@.", string, error.description];
|
|
[self log:message];
|
|
}
|
|
|
|
- (void)logFailedTest:( NSString *_Nonnull )reason {
|
|
[self log:[NSString stringWithFormat:@"FAILIURE: TEST FAILED - %@", reason]];
|
|
}
|
|
|
|
#pragma mark - IBAction
|
|
|
|
- (IBAction)userToUseDidChange:(UISegmentedControl *)sender {
|
|
_useUserInMemory = (sender.selectedSegmentIndex == 1);
|
|
}
|
|
|
|
- (IBAction)memoryPlus {
|
|
_userInMemory = [AppManager auth].currentUser;
|
|
[self updateUserInfo];
|
|
}
|
|
|
|
- (IBAction)memoryClear {
|
|
_userInMemory = nil;
|
|
[self updateUserInfo];
|
|
}
|
|
|
|
- (IBAction)clearConsole:(id)sender {
|
|
[_consoleString appendString:@"\n\n"];
|
|
_consoleTextView.text = @"";
|
|
}
|
|
|
|
- (IBAction)copyConsole:(id)sender {
|
|
UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
|
|
pasteboard.string = _consoleString ?: @"";
|
|
}
|
|
|
|
@end
|
|
|
|
NS_ASSUME_NONNULL_END
|