Skip to content

Commit

Permalink
Move LoginViewController to parts
Browse files Browse the repository at this point in the history
- The account selector now has Add Account item
- Last selected account is kept
- Account token refreshment is done on startup and on select if need
- Moved JIT status to LauncherMenuViewController's toolbar
- Primary View Controller is now LauncherSplitViewController
- More unmentioned(?), see diff.
  • Loading branch information
khanhduytran0 committed Dec 4, 2022
1 parent f1da61e commit 78b7882
Show file tree
Hide file tree
Showing 25 changed files with 495 additions and 569 deletions.
2 changes: 1 addition & 1 deletion Natives/AccountListViewController.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@


@property (nonatomic, copy) void (^whenDelete)(NSString* name);
@property(nonatomic, copy) void (^whenItemSelected)(NSString* name);
@property(nonatomic, copy) void (^whenItemSelected)();

@end
196 changes: 190 additions & 6 deletions Natives/AccountListViewController.m
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
#import <AuthenticationServices/AuthenticationServices.h>

#import "authenticator/BaseAuthenticator.h"
#import "AccountListViewController.h"
#import "AFNetworking.h"
#import "utils.h"
#import "LauncherPreferences.h"
#import "UIImageView+AFNetworking.h"
#import "ios_uikit_bridge.h"
#import "utils.h"

@interface ATableViewCell : UITableViewCell
@end
Expand All @@ -11,9 +16,10 @@ @implementation ATableViewCell
@end


@interface AccountListViewController()
@interface AccountListViewController()<ASWebAuthenticationPresentationContextProviding>

@property(nonatomic, strong) NSMutableArray *accountList;
@property(nonatomic) ASWebAuthenticationSession *authVC;

@end

Expand Down Expand Up @@ -46,7 +52,7 @@ - (void)viewDidLoad {

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.accountList.count;
return self.accountList.count + 1;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
Expand All @@ -57,6 +63,12 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"cell"];
}

if (indexPath.row == self.accountList.count) {
cell.imageView.image = [UIImage imageNamed:@"IconAdd"];
cell.textLabel.text = localize(@"login.option.add", nil);
return cell;
}

NSDictionary *selected = self.accountList[indexPath.row];
// By default, display the saved username
cell.textLabel.text = selected[@"username"];
Expand All @@ -78,9 +90,24 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[self dismissViewControllerAnimated:YES completion:nil];
[tableView deselectRowAtIndexPath:indexPath animated:NO];
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];

self.whenItemSelected(self.accountList[indexPath.row][@"username"]);
if (indexPath.row == self.accountList.count) {
[self actionAddAccount:cell];
return;
}

if (@available(iOS 13.0, *)) {
self.modalInPresentation = YES;
}
self.tableView.userInteractionEnabled = NO;
[self addActivityIndicatorTo:cell];

id callback = ^(NSString* status, BOOL success) {
[self callbackMicrosoftAuth:status success:success forCell:cell];
};
[[BaseAuthenticator loadSavedName:self.accountList[indexPath.row][@"username"]] refreshTokenWithCallback:callback];
}

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
Expand All @@ -91,17 +118,174 @@ - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEd
NSFileManager *fm = [NSFileManager defaultManager];
NSString *path = [NSString stringWithFormat:@"%s/accounts/%@.json", getenv("POJAV_HOME"), str];
if (self.whenDelete != nil) {
self.whenDelete(path);
self.whenDelete(str);
}
[fm removeItemAtPath:path error:nil];
[self.accountList removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
}

- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row == self.accountList.count) {
return UITableViewCellEditingStyleNone;
} else {
return UITableViewCellEditingStyleDelete;
}
}

- (void)actionAddAccount:(UITableViewCell *)sender {
UIAlertController *picker = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet];
UIAlertAction *actionMicrosoft = [UIAlertAction actionWithTitle:localize(@"login.option.microsoft", nil) style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
[self actionLoginMicrosoft:sender];
}];
[picker addAction:actionMicrosoft];
UIAlertAction *actionLocal = [UIAlertAction actionWithTitle:localize(@"login.option.local", nil) style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
[self actionLoginLocal:sender];
}];
[picker addAction:actionLocal];
UIAlertAction *cancel = [UIAlertAction actionWithTitle:localize(@"Cancel", nil) style:UIAlertActionStyleCancel handler:nil];
[picker addAction:cancel];

picker.popoverPresentationController.sourceView = sender;
picker.popoverPresentationController.sourceRect = sender.bounds;

[self presentViewController:picker animated:YES completion:nil];
}

- (void)actionLoginLocal:(UIView *)sender {
if ([getPreference(@"local_warn") boolValue] == YES) {
setPreference(@"local_warn", @NO);
UIAlertController *alert = [UIAlertController alertControllerWithTitle:localize(@"login.warn.title.localmode", nil) message:localize(@"login.warn.message.localmode", nil) preferredStyle:UIAlertControllerStyleActionSheet];
alert.popoverPresentationController.sourceView = sender;
alert.popoverPresentationController.sourceRect = sender.bounds;
UIAlertAction *ok = [UIAlertAction actionWithTitle:localize(@"OK", nil) style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {[self actionLoginLocal:sender];}];
[alert addAction:ok];
[self presentViewController:alert animated:YES completion:nil];
return;
}
UIAlertController *controller = [UIAlertController alertControllerWithTitle:localize(@"Sign in", nil) message:localize(@"login.option.local", nil) preferredStyle:UIAlertControllerStyleAlert];
[controller addTextFieldWithConfigurationHandler:^(UITextField *textField) {
textField.placeholder = localize(@"login.alert.field.username", nil);
textField.clearButtonMode = UITextFieldViewModeWhileEditing;
textField.borderStyle = UITextBorderStyleRoundedRect;
}];
[controller addAction:[UIAlertAction actionWithTitle:localize(@"OK", nil) style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
NSArray *textFields = controller.textFields;
UITextField *usernameField = textFields[0];
if (usernameField.text.length < 3 || usernameField.text.length > 16) {
controller.message = localize(@"login.error.username.outOfRange", nil);
[self presentViewController:controller animated:YES completion:nil];
} else {
id callback = ^(NSString* status, BOOL success) {
[self dismissViewControllerAnimated:YES completion:nil];
self.whenItemSelected();
};
[[[LocalAuthenticator alloc] initWithInput:usernameField.text] loginWithCallback:callback];
}
}]];
[controller addAction:[UIAlertAction actionWithTitle:localize(@"Cancel", nil) style:UIAlertActionStyleCancel handler:nil]];
[self presentViewController:controller animated:YES completion:nil];
}

- (void)actionLoginMicrosoft:(UITableViewCell *)sender {
NSURL *url = [NSURL URLWithString:@"https://login.live.com/oauth20_authorize.srf?client_id=00000000402b5328&response_type=code&scope=service%3A%3Auser.auth.xboxlive.com%3A%3AMBI_SSL&redirect_url=https%3A%2F%2Flogin.live.com%2Foauth20_desktop.srf"];

self.authVC =
[[ASWebAuthenticationSession alloc] initWithURL:url
callbackURLScheme:@"ms-xal-00000000402b5328"
completionHandler:^(NSURL * _Nullable callbackURL, NSError * _Nullable error)
{
if (callbackURL == nil) {
if (error.code != ASWebAuthenticationSessionErrorCodeCanceledLogin) {
showDialog(self, localize(@"Error", nil), error.localizedDescription);
}
return;
}
NSString *urlString = [callbackURL absoluteString];
// NSLog(@"URL returned = %@", [callbackURL absoluteString]);

if ([urlString containsString:@"/auth/?code="]) {
if (@available(iOS 13.0, *)) {
self.modalInPresentation = YES;
}
self.tableView.userInteractionEnabled = NO;
[self addActivityIndicatorTo:sender];
NSArray *components = [urlString componentsSeparatedByString:@"/auth/?code="];
id callback = ^(NSString* status, BOOL success) {
[self callbackMicrosoftAuth:status success:success forCell:sender];
};
[[[MicrosoftAuthenticator alloc] initWithInput:components[1]] loginWithCallback:callback];
} else {
NSArray *components = [urlString componentsSeparatedByString:@"/auth/?error="];
if ([components[1] hasPrefix:@"access_denied"]) {
// Ignore access denial responses
return;
}
NSString *outError = [components[1]
stringByReplacingOccurrencesOfString:@"&error_description=" withString:@": "];
outError = [outError stringByRemovingPercentEncoding];
showDialog(self, localize(@"Error", nil), outError);
}
}];

if (@available(iOS 13.0, *)) {
self.authVC.prefersEphemeralWebBrowserSession = YES;
self.authVC.presentationContextProvider = self;
}

if ([self.authVC start] == NO) {
showDialog(self, localize(@"Error", nil), @"Unable to open Safari");
}
}

- (void)addActivityIndicatorTo:(UITableViewCell *)cell {
UIActivityIndicatorViewStyle indicatorStyle;
if (@available(iOS 13.0, *)) {
indicatorStyle = UIActivityIndicatorViewStyleMedium;
} else {
indicatorStyle = UIActivityIndicatorViewStyleGray;
}
UIActivityIndicatorView *indicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:indicatorStyle];
cell.accessoryView = indicator;
[indicator sizeToFit];
[indicator startAnimating];
}

- (void)removeActivityIndicatorFrom:(UITableViewCell *)cell {
UIActivityIndicatorView *indicator = (id)cell.accessoryView;
[indicator stopAnimating];
cell.accessoryView = nil;
}

- (void)callbackMicrosoftAuth:(NSString *)status success:(BOOL)success forCell:(UITableViewCell *)cell {
if (status != nil) {
cell.detailTextLabel.text = status;
if (!success) {
if (@available(iOS 13.0, *)) {
self.modalInPresentation = NO;
}
self.tableView.userInteractionEnabled = YES;
[self removeActivityIndicatorFrom:cell];
NSLog(@"[MSA] Error: %@", status);
showDialog(self, localize(@"Error", nil), status);
}
} else if (success) {
[self removeActivityIndicatorFrom:cell];
[self dismissViewControllerAnimated:YES completion:nil];
self.whenItemSelected();
}
}

#pragma mark - UIPopoverPresentationControllerDelegate
- (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller traitCollection:(UITraitCollection *)traitCollection {
return UIModalPresentationNone;
}

#pragma mark - ASWebAuthenticationPresentationContextProviding
- (ASPresentationAnchor)presentationAnchorForWebAuthenticationSession:(ASWebAuthenticationSession *)session API_AVAILABLE(ios(13.0)){
return UIApplication.sharedApplication.windows.firstObject;
}

@end
7 changes: 0 additions & 7 deletions Natives/AppDelegate.m
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#import "AppDelegate.h"
#import "LoginViewController.h"
#import "SceneDelegate.h"
#import "ios_uikit_bridge.h"
#import "utils.h"
Expand Down Expand Up @@ -36,12 +35,6 @@ - (void)application:(UIApplication *)application didDiscardSceneSessions:(NSSet<
// Use this method to release any resources that were specific to the discarded scenes, as they will not return.
}

- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
NSDictionary *data = [NSDictionary dictionaryWithObject:url forKey:@"url"];
[[NSNotificationCenter defaultCenter] postNotificationName:@"MSALoginCallback" object:self userInfo:data];
return YES;
}

- (void)applicationDidBecomeActive:(UIApplication *)application {
CallbackBridge_setWindowAttrib(GLFW_FOCUSED, 1);
}
Expand Down
12 changes: 12 additions & 0 deletions Natives/Assets.xcassets/IconAdd.imageset/Contents.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "icon.png",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Binary file added Natives/Assets.xcassets/IconAdd.imageset/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 12 additions & 0 deletions Natives/Assets.xcassets/SpinnerArrow.imageset/Contents.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "icon.png",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 0 additions & 1 deletion Natives/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,6 @@ add_executable(PojavLauncher
LauncherPreferencesViewController.m
LauncherPrefGameDirViewController.m
LauncherSplitViewController.m
LoginViewController.m
MinecraftResourceUtils.m
SceneDelegate.m
SceneExternalDelegate.m
Expand Down
Loading

0 comments on commit 78b7882

Please sign in to comment.