Files
2025-09-18 17:55:52 -04:00

534 lines
22 KiB
Objective-C

//
// RBBaseViewController.m
// RobloxMobile
//
// Created by Christian Hresko on 6/23/14.
// Copyright (c) 2014 ROBLOX. All rights reserved.
//
#import "RBBaseViewController.h"
#import "RBBarButtonMenu.h"
#import "RobloxInfo.h"
#import "UserInfo.h"
#import "RBPurchaseViewController.h"
#import "RBAccountManagerViewController.h"
#import "UIAlertView+Blocks.h"
#import "LoginManager.h"
#import "Flurry.h"
#import "RBMobileWebViewController.h"
#import "RBGameViewController.h"
#import "RBProfileViewController.h"
#import "RBModalPopUpViewController.h"
#import "RBWebGamePreviewScreenController.h"
#import "RBWebProfileViewController.h"
#import "SearchResultCollectionViewController.h"
#import "NativeSearchNavItem.h"
#import "RobloxNotifications.h"
#import "UIView+Position.h"
//---METRICS---
@interface RBBaseViewController ()
@end
@implementation RBBaseViewController
- (void) setViewTheme:(RBXTheme)theme
{
viewTheme = theme;
[RobloxTheme applyTheme:viewTheme toViewController:self quickly:YES];
}
- (void) setFlurryEventsForExternalLinkEvent:(NSString*)webExternalLinkEvent
andWebViewEvent:(NSString*)webLocalLinkEvent
andOpenProfileEvent:(NSString*)webProfileLinkEvent
andOpenGameDetailEvent:(NSString*)webGameDetailLinkEvent
{
_flurryOpenExternalLinkEvent = webExternalLinkEvent;
_flurryOpenWebViewEvent = webLocalLinkEvent;
_flurryOpenProfileEvent = webProfileLinkEvent;
_flurryOpenGameDetailEvent = webGameDetailLinkEvent;
}
- (void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
if (viewTheme)
[RobloxTheme applyTheme:viewTheme toViewController:self quickly:YES];
if (addSearchListeners)
{
//Games
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(displaySelectedGame:) name:RBXNotificationGameSelected object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(displayGameSearchResults:) name:RBXNotificationSearchGames object:nil];
//Users
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(displayUserSearchResults:) name:RBXNotificationSearchUsers object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(displaySelectedUser:) name:RBXNotificationUserSelected object:nil];
}
}
- (void) viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
if (viewTheme)
[RobloxTheme applyTheme:viewTheme toViewController:self quickly:NO];
}
- (void) viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
if (addSearchListeners)
{
//Games
[[NSNotificationCenter defaultCenter] removeObserver:self name:RBXNotificationGameSelected object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:RBXNotificationSearchGames object:nil];
//Users
[[NSNotificationCenter defaultCenter] removeObserver:self name:RBXNotificationSearchUsers object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:RBXNotificationUserSelected object:nil];
}
}
//Navigation buttons
- (void) addRobuxIconWithFlurryEvent:(NSString*)RobuxEvent
andBCIconWithFlurryEvent:(NSString*)BCEvent
{
//define some events to be fired
_flurryEventRobux = RobuxEvent;
_flurryEventBuildersClub = BCEvent;
UIImage* rbxImage = [UIImage imageNamed:@"Icon Robux Off"];
UIImage* rbxImageDown = [UIImage imageNamed:@"Icon Robux On"];
UIImage* bcImage = [UIImage imageNamed:@"Icon BC Off"];
UIImage* bcImageDown = [UIImage imageNamed:@"Icon BC On"];
if ([RobloxInfo thisDeviceIsATablet])
{
//create the buttons
UIBarButtonItem* buyRBXButtonItem = [[UIBarButtonItem alloc] initWithImage:rbxImage
style:UIBarButtonItemStylePlain
target:self
action:@selector(didPressBuyRobux)];
[buyRBXButtonItem setBackgroundImage:rbxImageDown forState:UIControlStateSelected barMetrics:UIBarMetricsDefault];
UIBarButtonItem* buyBCButtonItem = [[UIBarButtonItem alloc] initWithImage:bcImage
style:UIBarButtonItemStylePlain
target:self
action:@selector(didPressBuildersClub)];
[buyBCButtonItem setBackgroundImage:bcImageDown forState:UIControlStateSelected barMetrics:UIBarMetricsDefault];
//insert the buttons at the head of the list of existing buttons
NSMutableArray* buttons = [NSMutableArray arrayWithArray:@[buyBCButtonItem, buyRBXButtonItem]];
[buttons addObjectsFromArray:self.navigationItem.rightBarButtonItems];
[self.navigationItem setRightBarButtonItems:buttons];
}
else
{
//If we're on phone, we don't have as much space
CGRect buttonFrame = CGRectMake(0, 0, 28, 28);
CGRect layoutFrame = CGRectMake(0, 0, 64, 28);
//so make a custom view to space the icons closer
UIButton* btnRBX = [UIButton buttonWithType:UIButtonTypeCustom];
[btnRBX setImage:rbxImage forState:UIControlStateNormal];
[btnRBX setImage:rbxImageDown forState:UIControlStateSelected];
[btnRBX addTarget:self action:@selector(didPressBuyRobux) forControlEvents:UIControlEventTouchUpInside];
[btnRBX setFrame:buttonFrame];
UIButton* btnBC = [UIButton buttonWithType:UIButtonTypeCustom];
[btnBC setImage:bcImage forState:UIControlStateNormal];
[btnBC setImage:bcImageDown forState:UIControlStateSelected];
[btnBC addTarget:self action:@selector(didPressBuildersClub) forControlEvents:UIControlEventTouchUpInside];
[btnBC setFrame:buttonFrame];
[btnBC setX:layoutFrame.size.width - btnBC.width];
UIView* customLayout = [[UIView alloc] initWithFrame:layoutFrame];
[customLayout addSubview:btnBC];
[customLayout addSubview:btnRBX];
UIBarButtonItem* customBtn = [[UIBarButtonItem alloc] initWithCustomView:customLayout];
NSMutableArray* buttons = [NSMutableArray arrayWithArray:@[customBtn]];
[buttons addObjectsFromArray:self.navigationItem.rightBarButtonItems];
[self.navigationItem setRightBarButtonItems:buttons];
}
}
- (void) addSearchIconWithSearchType:(SearchResultType)searchType
andFlurryEvent:(NSString*)searchEvent
{
addSearchListeners = YES;
bool compact = ![RobloxInfo thisDeviceIsATablet];
NativeSearchNavItem* searchItem = [[NativeSearchNavItem alloc] initWithSearchType:searchType andContainer:self compactMode:compact];
NSArray* rightNavItems = self.navigationItem.rightBarButtonItems;
NSMutableArray* items = [NSMutableArray arrayWithArray:rightNavItems];
[items addObject:searchItem];
[self.navigationItem setRightBarButtonItems:items];
}
- (void) addLogoutButton
{
UIBarButtonItem* logoutButton = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"Logout Button"]
style:UIBarButtonItemStylePlain
target:self
action:@selector(didPressLogOut)];
//insert the buttons at the head of the list of existing buttons
NSMutableArray* buttons = [NSMutableArray arrayWithObject:logoutButton];
[buttons addObjectsFromArray:self.navigationItem.rightBarButtonItems];
[self.navigationItem setRightBarButtonItems:buttons];
}
//Navigation Button Events
- (void)didPressEditAccount
{
#define ACCOUNT_SETTINGS_POPUP_SIZE CGRectMake(0, 0, 540, 344)
if (_flurryEventEditAccount)
[Flurry logEvent:_flurryEventEditAccount];
NSString* storyboardName = [RobloxInfo getStoryboardName];
UIStoryboard* storyboard = [UIStoryboard storyboardWithName:storyboardName bundle:nil];
RBAccountManagerViewController* controller = [storyboard instantiateViewControllerWithIdentifier:@"RBAccountManagerController"];
UINavigationController* navigation = [[UINavigationController alloc] initWithRootViewController:controller];
navigation.modalPresentationStyle = UIModalPresentationFormSheet;
[self.navigationController presentViewController:navigation animated:YES completion:nil];
navigation.view.superview.bounds = ACCOUNT_SETTINGS_POPUP_SIZE;
}
- (void)didPressLogOut
{
if (_flurryEventLogOut)
[Flurry logEvent:_flurryEventLogOut];
UIAlertView* view = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Log Out", nil)
message:NSLocalizedString(@"Are you sure you want to log out?", nil)
delegate:nil
cancelButtonTitle:NSLocalizedString(@"Cancel", nil)
otherButtonTitles:NSLocalizedString(@"Log Out", nil) , nil];
RBBaseViewController* strongSelf = self;
[view showWithCompletion:^(UIAlertView *alertView, NSInteger buttonIndex)
{
switch (buttonIndex)
{
case 0:
break;
case 1:
{
[[LoginManager sharedInstance] doLogout];
[strongSelf.tabBarController.navigationController popViewControllerAnimated:YES];
break;
}
default:
break;
}
}];
}
- (void) didPressBuyRobux
{
CGRect PURCHASE_ROBUX_POPUP_SIZE = [RobloxInfo thisDeviceIsATablet] ? CGRectMake(0, 0, 540, 344) : CGRectMake(0, 0, 300, 344);
if (_flurryEventRobux)
[Flurry logEvent:_flurryEventRobux];
NSString* baseURL = [RobloxInfo getBaseUrl];
NSString* url = [baseURL stringByAppendingString:@"mobile-app-upgrades/native-ios/robux"];
if (![RobloxInfo thisDeviceIsATablet])
url = [url stringByReplacingOccurrencesOfString:@"m." withString:@"www."];
NSString* titleString = [NSString stringWithFormat:@"%@ : R$%@", NSLocalizedString(@"CurrentRobuxBalanceWord", nil), [UserInfo CurrentPlayer].Robux];
RBPurchaseViewController* controller = [[RBPurchaseViewController alloc] initWithURL:[NSURL URLWithString:url] andTitle:titleString];
UINavigationController* navigation = [[UINavigationController alloc] initWithRootViewController:controller];
navigation.modalPresentationStyle = UIModalPresentationFormSheet;
[self.navigationController presentViewController:navigation animated:YES completion:nil];
navigation.view.superview.bounds = PURCHASE_ROBUX_POPUP_SIZE;
}
- (void) didPressBuildersClub
{
if (_flurryEventBuildersClub)
[Flurry logEvent:_flurryEventBuildersClub];
NSString* baseUrl = [RobloxInfo getBaseUrl];
NSString* url = [baseUrl stringByAppendingString:@"mobile-app-upgrades/native-ios/bc"];
if (![RobloxInfo thisDeviceIsATablet])
url = [url stringByReplacingOccurrencesOfString:@"m." withString:@"www."];
//NSString* BCLevelKey = @"NBCWord";
//[UserInfo CurrentPlayer].bcMember
NSString* titleString = NSLocalizedString(@"Builders Club", nil); //[NSString stringWithFormat:@"%@ : %@", NSLocalizedString(@"CurrentBuildersClubWord", nil), NSLocalizedString(BCLevelKey, nil)];
RBPurchaseViewController* controller = [[RBPurchaseViewController alloc] initWithURL:[NSURL URLWithString:url] andTitle:titleString];
UINavigationController* navigation = [[UINavigationController alloc] initWithRootViewController:controller];
navigation.modalPresentationStyle = UIModalPresentationFormSheet;
[self.navigationController presentViewController:navigation animated:YES completion:nil];
}
//pushing view controllers
-(RBXWebRequestReturnStatus) handleWebRequest:(NSURL*)aRequest
{
//typically called from a webview shouldLoadWithRequest delegate function
//returns RBXWebRequestReturnWebRequest when the webview can safely load the requested URL
//returns RBXWebRequestReturnScreenPush when the request has opened another view
//returns RBXWebRequestReturnUnknown when the domain is unknown and should be handled by pushing out to the browser
NSString* lcaseHost = [[aRequest host] lowercaseString];
NSString* aRequestString = [[NSString stringWithFormat:@"%@", aRequest] stringByRemovingPercentEncoding];
aRequestString = [aRequestString lowercaseString];
//check the domain of the URL to see if it is a ROBLOX URL
bool isRobloxURL = [lcaseHost rangeOfString:@"roblox"].location != NSNotFound;
//also check that the url isn't a Roblox User's URL from a message
bool isUserURL = [aRequestString rangeOfString:@"user.aspx?id="].location != NSNotFound;
if (isRobloxURL || isUserURL)
{
if (isUserURL)
{
[self pushProfileControllerWithURL:aRequestString];
return RBXWebRequestReturnScreenPush;
}
else if ([aRequestString rangeOfString:@"/users/"].location != NSNotFound)
{
[self setViewTheme:RBXThemeCreative];
}
else if ([aRequestString rangeOfString:@"-place?id="].location != NSNotFound)
{
[self pushGameDetailWithURL:aRequestString];
return RBXWebRequestReturnScreenPush;
}
else if ([aRequestString rangeOfString:@"-item?id="].location != NSNotFound)
{
[self setViewTheme:RBXThemeGame];
}
else if ([aRequestString rangeOfString:@"/catalog/"].location != NSNotFound)
{
[self setViewTheme:RBXThemeGame];
}
else if ([aRequestString rangeOfString:@"groups.aspx"].location != NSNotFound)
{
[self setViewTheme:RBXThemeSocial];
}
else if ([aRequestString rangeOfString:@"stuff.aspx"].location != NSNotFound)
{
[self setViewTheme:RBXThemeGame];
}
else if ([aRequestString rangeOfString:@"inventory"].location != NSNotFound)
{
[self setViewTheme:RBXThemeGame];
}
else if ([aRequestString rangeOfString:@"/forum/"].location != NSNotFound)
{
[self setViewTheme:RBXThemeSocial];
}
return RBXWebRequestReturnWebRequest;
}
else
{
//Not exactly sure what we found... just open it in an external web view.
//[[UIApplication sharedApplication] openURL:aRequest];
return RBXWebRequestReturnUnknown;
}
return RBXWebRequestReturnWebRequest;
}
-(void) handleWebRequestWithPopout:(NSURL*)aRequest
{
NSString* lcaseHost = [[aRequest host] lowercaseString];
NSString* aRequestString = [[NSString stringWithFormat:@"%@", aRequest] stringByRemovingPercentEncoding];
aRequestString = [aRequestString lowercaseString];
bool isRobloxURL = [lcaseHost rangeOfString:@"roblox"].location != NSNotFound;
bool isUserURL = [aRequestString rangeOfString:@"user.aspx?id="].location != NSNotFound;
if (isRobloxURL || isUserURL)
{
if (isUserURL)
{
[self pushProfileControllerWithURL:aRequestString];
}
else if ([aRequestString rangeOfString:@"-place?id="].location != NSNotFound)
{
[self pushGameDetailWithURL:aRequestString];
}
else if ([aRequestString rangeOfString:@"-item?id="].location != NSNotFound)
{
[self pushWebControllerwithURL:aRequestString andTheme:RBXThemeGame];
}
else if ([aRequestString rangeOfString:@"groups.aspx"].location != NSNotFound)
{
[self pushWebControllerwithURL:aRequestString andTheme:RBXThemeSocial];
}
else if ([aRequestString rangeOfString:@"stuff.aspx"].location != NSNotFound)
{
[self pushWebControllerwithURL:aRequestString andTheme:RBXThemeGame];
}
else
{
//Not exactly sure what we found... just open it in an external web view.
if (_flurryOpenExternalLinkEvent)
[Flurry logEvent:_flurryOpenExternalLinkEvent];
[[UIApplication sharedApplication] openURL:aRequest];
}
}
else
{
if (_flurryOpenExternalLinkEvent)
[Flurry logEvent:_flurryOpenExternalLinkEvent];
[[UIApplication sharedApplication] openURL:aRequest];
}
}
-(void) pushWebControllerwithURL:(NSString*)stringURL andTheme:(RBXTheme)theme
{
[self pushWebControllerwithURL:stringURL andTitle:nil andTheme:theme];
}
-(void) pushWebControllerwithURL:(NSString*)stringURL andTitle:(NSString*)pageTitle andTheme:(RBXTheme)theme
{
if (_flurryOpenWebViewEvent)
[Flurry logEvent:_flurryOpenWebViewEvent];
RBMobileWebViewController* aWebScreen = [[RBMobileWebViewController alloc] initWithNavButtons:NO];
[aWebScreen.view setFrame:CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y, self.view.frame.size.width, self.view.frame.size.height)];
[aWebScreen setUrl:stringURL];
[aWebScreen setViewTheme:theme];
if (pageTitle)
[aWebScreen setTitle:pageTitle];
[self.navigationController pushViewController:aWebScreen animated:YES];
}
//Profile
-(void) pushProfileControllerWithUserID:(NSNumber*)userID
{
if (_flurryOpenProfileEvent)
[Flurry logEvent:_flurryOpenProfileEvent];
if ([RobloxInfo thisDeviceIsATablet])
{
NSString* storyboardName = [RobloxInfo getStoryboardName];
UIStoryboard* sb = [UIStoryboard storyboardWithName:storyboardName bundle:nil];
RBProfileViewController* builderProfile = (RBProfileViewController*) [sb instantiateViewControllerWithIdentifier:@"RBOthersProfileViewController"];
builderProfile.userId = userID;
[self.navigationController pushViewController:builderProfile animated:YES];
}
else
{
RBWebProfileViewController* builderProfile = [[RBWebProfileViewController alloc] initWithNavButtons:YES];
builderProfile.userId = userID;
[builderProfile setViewTheme:RBXThemeCreative];
[self.navigationController pushViewController:builderProfile animated:YES];
}
}
-(void) pushProfileControllerWithURL:(NSString*)stringURL
{
//NOTE - flurry events are handled in other functions
NSArray* stringParts = [stringURL componentsSeparatedByString:@"user.aspx?id="];
if ([stringParts count] <= 1)
{
//failed to parse the url, fallback and use a mobile web view
[self pushWebControllerwithURL:stringURL andTheme:RBXThemeCreative];
return;
}
NSNumber* userID = [NSNumber numberWithInt:[stringParts[1] integerValue]];
[self pushProfileControllerWithUserID:userID];
}
//Games
-(void) pushGameDetailWithURL:(NSString*)stringURL
{
//load up a game
NSArray* stringParts = [stringURL componentsSeparatedByString:@"?id="];
if ([stringParts count] <= 1)
{
//failed to parse the url, fallback and use a mobile web view
[self pushWebControllerwithURL:stringURL andTheme:RBXThemeGame];
}
else
{
//grab the game details
[RobloxData fetchGameDetails:stringParts[1] completion:^(RBXGameData *game)
{
[self pushGameDetailWithGameData:game];
}];
}
}
-(void) pushGameDetailWithGameData:(RBXGameData*)game
{
if ([RobloxInfo thisDeviceIsATablet])
{
if (_flurryOpenGameDetailEvent)
[Flurry logEvent:_flurryOpenGameDetailEvent];
dispatch_async(dispatch_get_main_queue(), ^
{
RBWebGamePreviewScreenController* aGameScreen = [[RBWebGamePreviewScreenController alloc] init];
aGameScreen.gameData = game;
[self.navigationController pushViewController:aGameScreen animated:YES];
});
}
else
{
[self pushGameWithID:game.placeID.intValue isUser:NO];
}
}
-(void) pushGameWithID:(int)placeID isUser:(BOOL)isUser
{
RBGameViewController* controller = [[RBGameViewController alloc] init];
controller.placeID = placeID;
controller.isUser = isUser;
[self presentViewController:controller animated:NO completion:nil];
}
//Search
-(void) pushSearchResultsType:(SearchResultType)resultType
withKeyword:(NSString*)searchKeywords
{
SearchResultCollectionViewController* aCollectionViewController = [[SearchResultCollectionViewController alloc] initWithKeyword:searchKeywords andSearchType:resultType];
[self.navigationController pushViewController:aCollectionViewController animated:YES];
}
//search result functions
- (void) displaySelectedGame:(NSNotification*)notification
{
RBXGameData* notificationData = (RBXGameData*)[notification.userInfo objectForKey:@"gameData"];
[self pushGameDetailWithGameData:notificationData];
}
- (void) displayGameSearchResults:(NSNotification*) notification
{
//[Flurry logEvent:GS_searchGames];
NSString* keywords = [notification.userInfo objectForKey:@"keywords"];
//[self performSegueWithIdentifier:@"searchResults" sender:keywords]; //NOTE- THIS WAY IS DEPRECATED BUT IT OPENS A SPECIFIC SEARCH RESULT SCREEN
//GameSearchResultsScreenController* controller = segue.destinationViewController;
//controller.keywords = (NSString*) sender;
//This is how it should be done - later
[self pushSearchResultsType:SearchResultGames withKeyword:keywords];
}
- (void) displaySelectedUser:(NSNotification*) notification
{
RBXUserSearchInfo* user = (RBXUserSearchInfo*)[notification.userInfo objectForKey:@"userData"];
[self pushProfileControllerWithUserID:user.userId];
}
- (void) displayUserSearchResults:(NSNotification*) notification
{
//NSLog(@"Displaying User Search Results with notification : %@", notification);
NSString* searchKeywords = (NSString*)[notification.userInfo objectForKey:@"keywords"];
[self pushSearchResultsType:SearchResultUsers withKeyword:searchKeywords];
}
@end