Path: blob/main/Natives/LauncherPreferencesViewController.m
589 views
#import <Foundation/Foundation.h>12#import "DBNumberedSlider.h"3#import "HostManagerBridge.h"4#import "LauncherNavigationController.h"5#import "LauncherMenuViewController.h"6#import "LauncherPreferences.h"7#import "LauncherPreferencesViewController.h"8#import "LauncherPrefContCfgViewController.h"9#import "LauncherPrefManageJREViewController.h"10#import "UIKit+hook.h"1112#import "config.h"13#import "ios_uikit_bridge.h"14#import "utils.h"1516@interface LauncherPreferencesViewController()17@property(nonatomic) NSArray<NSString*> *rendererKeys, *rendererList;18@end1920@implementation LauncherPreferencesViewController2122- (id)init {23self = [super init];24self.title = localize(@"Settings", nil);25return self;26}2728- (NSString *)imageName {29return @"MenuSettings";30}3132- (void)viewDidLoad33{34self.getPreference = ^id(NSString *section, NSString *key){35NSString *keyFull = [NSString stringWithFormat:@"%@.%@", section, key];36return getPrefObject(keyFull);37};38self.setPreference = ^(NSString *section, NSString *key, id value){39NSString *keyFull = [NSString stringWithFormat:@"%@.%@", section, key];40setPrefObject(keyFull, value);41};4243self.hasDetail = YES;44self.prefDetailVisible = self.navigationController == nil;4546self.prefSections = @[@"general", @"video", @"control", @"java", @"debug"];4748self.rendererKeys = getRendererKeys(NO);49self.rendererList = getRendererNames(NO);5051BOOL(^whenNotInGame)() = ^BOOL(){52return self.navigationController != nil;53};54self.prefContents = @[55@[56// General settings57@{@"icon": @"cube"},58@{@"key": @"check_sha",59@"hasDetail": @YES,60@"icon": @"lock.shield",61@"type": self.typeSwitch,62@"enableCondition": whenNotInGame63},64@{@"key": @"cosmetica",65@"hasDetail": @YES,66@"icon": @"eyeglasses",67@"type": self.typeSwitch,68@"enableCondition": whenNotInGame69},70@{@"key": @"debug_logging",71@"hasDetail": @YES,72@"icon": @"doc.badge.gearshape",73@"type": self.typeSwitch,74@"action": ^(BOOL enabled){75debugLogEnabled = enabled;76NSLog(@"[Debugging] Debug log enabled: %@", enabled ? @"YES" : @"NO");77}78},79@{@"key": @"appicon",80@"hasDetail": @YES,81@"icon": @"paintbrush",82@"type": self.typePickField,83@"enableCondition": ^BOOL(){84return UIApplication.sharedApplication.supportsAlternateIcons;85},86@"action": ^void(NSString *iconName) {87if ([iconName isEqualToString:@"AppIcon-Light"]) {88iconName = nil;89}90[UIApplication.sharedApplication setAlternateIconName:iconName completionHandler:^(NSError * _Nullable error) {91if (error == nil) return;92NSLog(@"Error in appicon: %@", error);93showDialog(localize(@"Error", nil), error.localizedDescription);94}];95},96@"pickKeys": @[97@"AppIcon-Light",98@"AppIcon-Dark",99@"AppIcon-Development"100],101@"pickList": @[102localize(@"preference.title.appicon-default", nil),103localize(@"preference.title.appicon-dark", nil),104localize(@"preference.title.appicon-development", nil)105]106},107@{@"key": @"hidden_sidebar",108@"hasDetail": @YES,109@"icon": @"sidebar.leading",110@"type": self.typeSwitch,111@"enableCondition": whenNotInGame112},113@{@"key": @"reset_warnings",114@"icon": @"exclamationmark.triangle",115@"type": self.typeButton,116@"enableCondition": whenNotInGame,117@"action": ^void(){118resetWarnings();119}120},121@{@"key": @"reset_settings",122@"icon": @"trash",123@"type": self.typeButton,124@"enableCondition": whenNotInGame,125@"requestReload": @YES,126@"showConfirmPrompt": @YES,127@"destructive": @YES,128@"action": ^void(){129loadPreferences(YES);130[self.tableView reloadData];131}132},133@{@"key": @"erase_demo_data",134@"icon": @"trash",135@"type": self.typeButton,136@"enableCondition": ^BOOL(){137NSString *demoPath = [NSString stringWithFormat:@"%s/.demo", getenv("POJAV_HOME")];138int count = [NSFileManager.defaultManager contentsOfDirectoryAtPath:demoPath error:nil].count;139return whenNotInGame() && count > 0;140},141@"showConfirmPrompt": @YES,142@"destructive": @YES,143@"action": ^void(){144NSString *demoPath = [NSString stringWithFormat:@"%s/.demo", getenv("POJAV_HOME")];145NSError *error;146if([NSFileManager.defaultManager removeItemAtPath:demoPath error:&error]) {147[NSFileManager.defaultManager createDirectoryAtPath:demoPath148withIntermediateDirectories:YES attributes:nil error:nil];149[NSFileManager.defaultManager changeCurrentDirectoryPath:demoPath];150if (getenv("DEMO_LOCK")) {151[(LauncherNavigationController *)self.navigationController fetchLocalVersionList];152}153} else {154NSLog(@"Error in erase_demo_data: %@", error);155showDialog(localize(@"Error", nil), error.localizedDescription);156}157}158}159], @[160// Video and renderer settings161@{@"icon": @"video"},162@{@"key": @"renderer",163@"hasDetail": @YES,164@"icon": @"cpu",165@"type": self.typePickField,166@"enableCondition": whenNotInGame,167@"pickKeys": self.rendererKeys,168@"pickList": self.rendererList169},170@{@"key": @"resolution",171@"hasDetail": @YES,172@"icon": @"viewfinder",173@"type": self.typeSlider,174@"min": @(25),175@"max": @(150)176},177@{@"key": @"max_framerate",178@"hasDetail": @YES,179@"icon": @"timelapse",180@"type": self.typeSwitch,181@"enableCondition": ^BOOL(){182return whenNotInGame() && (UIScreen.mainScreen.maximumFramesPerSecond > 60);183}184},185@{@"key": @"performance_hud",186@"hasDetail": @YES,187@"icon": @"waveform.path.ecg",188@"type": self.typeSwitch,189@"enableCondition": ^BOOL(){190return [CAMetalLayer instancesRespondToSelector:@selector(developerHUDProperties)];191}192},193@{@"key": @"fullscreen_airplay",194@"hasDetail": @YES,195@"icon": @"airplayvideo",196@"type": self.typeSwitch,197@"action": ^(BOOL enabled){198if (self.navigationController != nil) return;199if (UIApplication.sharedApplication.connectedScenes.count < 2) return;200if (enabled) {201[self.presentingViewController performSelector:@selector(switchToExternalDisplay)];202} else {203[self.presentingViewController performSelector:@selector(switchToInternalDisplay)];204}205}206},207@{@"key": @"silence_other_audio",208@"hasDetail": @YES,209@"icon": @"speaker.slash",210@"type": self.typeSwitch211},212@{@"key": @"silence_with_switch",213@"hasDetail": @YES,214@"icon": @"speaker.zzz",215@"type": self.typeSwitch216},217], @[218// Control settings219@{@"icon": @"gamecontroller"},220@{@"key": @"default_gamepad_ctrl",221@"icon": @"hammer",222@"type": self.typeChildPane,223@"enableCondition": whenNotInGame,224@"canDismissWithSwipe": @NO,225@"class": LauncherPrefContCfgViewController.class226},227@{@"key": @"hardware_hide",228@"icon": @"eye.slash",229@"hasDetail": @YES,230@"type": self.typeSwitch,231},232@{@"key": @"recording_hide",233@"icon": @"eye.slash",234@"hasDetail": @YES,235@"type": self.typeSwitch,236},237@{@"key": @"gesture_mouse",238@"icon": @"cursorarrow.click",239@"hasDetail": @YES,240@"type": self.typeSwitch,241},242@{@"key": @"gesture_hotbar",243@"icon": @"hand.tap",244@"hasDetail": @YES,245@"type": self.typeSwitch,246},247@{@"key": @"disable_haptics",248@"icon": @"wave.3.left",249@"hasDetail": @NO,250@"type": self.typeSwitch,251},252@{@"key": @"slideable_hotbar",253@"hasDetail": @YES,254@"icon": @"slider.horizontal.below.rectangle",255@"type": self.typeSwitch256},257@{@"key": @"press_duration",258@"hasDetail": @YES,259@"icon": @"cursorarrow.click.badge.clock",260@"type": self.typeSlider,261@"min": @(100),262@"max": @(1000),263},264@{@"key": @"button_scale",265@"hasDetail": @YES,266@"icon": @"aspectratio",267@"type": self.typeSlider,268@"min": @(50), // 80?269@"max": @(500)270},271@{@"key": @"mouse_scale",272@"hasDetail": @YES,273@"icon": @"arrow.up.left.and.arrow.down.right.circle",274@"type": self.typeSlider,275@"min": @(25),276@"max": @(300)277},278@{@"key": @"mouse_speed",279@"hasDetail": @YES,280@"icon": @"cursorarrow.motionlines",281@"type": self.typeSlider,282@"min": @(25),283@"max": @(300)284},285@{@"key": @"virtmouse_enable",286@"hasDetail": @YES,287@"icon": @"cursorarrow.rays",288@"type": self.typeSwitch289},290@{@"key": @"gyroscope_enable",291@"hasDetail": @YES,292@"icon": @"gyroscope",293@"type": self.typeSwitch,294@"enableCondition": ^BOOL(){295return realUIIdiom != UIUserInterfaceIdiomTV;296}297},298@{@"key": @"gyroscope_invert_x_axis",299@"hasDetail": @YES,300@"icon": @"arrow.left.and.right",301@"type": self.typeSwitch,302@"enableCondition": ^BOOL(){303return realUIIdiom != UIUserInterfaceIdiomTV;304}305},306@{@"key": @"gyroscope_sensitivity",307@"hasDetail": @YES,308@"icon": @"move.3d",309@"type": self.typeSlider,310@"min": @(50),311@"max": @(300),312@"enableCondition": ^BOOL(){313return realUIIdiom != UIUserInterfaceIdiomTV;314}315}316], @[317// Java tweaks318@{@"icon": @"sparkles"},319@{@"key": @"manage_runtime",320@"hasDetail": @YES,321@"icon": @"cube",322@"type": self.typeChildPane,323@"canDismissWithSwipe": @YES,324@"class": LauncherPrefManageJREViewController.class,325@"enableCondition": whenNotInGame326},327@{@"key": @"java_args",328@"hasDetail": @YES,329@"icon": @"slider.vertical.3",330@"type": self.typeTextField,331@"enableCondition": whenNotInGame332},333@{@"key": @"env_variables",334@"hasDetail": @YES,335@"icon": @"terminal",336@"type": self.typeTextField,337@"enableCondition": whenNotInGame338},339@{@"key": @"auto_ram",340@"hasDetail": @YES,341@"icon": @"slider.horizontal.3",342@"type": self.typeSwitch,343@"enableCondition": whenNotInGame,344@"warnCondition": ^BOOL(){345return !isJailbroken;346},347@"warnKey": @"auto_ram_warn",348@"requestReload": @YES349},350@{@"key": @"allocated_memory",351@"hasDetail": @YES,352@"icon": @"memorychip",353@"type": self.typeSlider,354@"min": @(250),355@"max": @((NSProcessInfo.processInfo.physicalMemory / 1048576) * 0.85),356@"enableCondition": ^BOOL(){357return ![self.getPreference(@"java", @"auto_ram") boolValue] && whenNotInGame();358},359@"warnCondition": ^BOOL(DBNumberedSlider *view){360return view.value >= NSProcessInfo.processInfo.physicalMemory / 1048576 * 0.37;361},362@"warnKey": @"mem_warn"363}364], @[365// Debug settings - only recommended for developer use366@{@"icon": @"ladybug"},367@{@"key": @"debug_skip_wait_jit",368@"hasDetail": @YES,369@"icon": @"forward",370@"type": self.typeSwitch,371@"enableCondition": whenNotInGame372},373@{@"key": @"debug_hide_home_indicator",374@"hasDetail": @YES,375@"icon": @"iphone.and.arrow.forward",376@"type": self.typeSwitch,377@"enableCondition": ^BOOL(){378return379self.splitViewController.view.safeAreaInsets.bottom > 0 ||380self.view.safeAreaInsets.bottom > 0;381}382},383@{@"key": @"debug_ipad_ui",384@"hasDetail": @YES,385@"icon": @"ipad",386@"type": self.typeSwitch,387@"enableCondition": whenNotInGame388},389@{@"key": @"debug_auto_correction",390@"hasDetail": @YES,391@"icon": @"textformat.abc.dottedunderline",392@"type": self.typeSwitch393}394]395];396397[super viewDidLoad];398if (self.navigationController == nil) {399self.tableView.alpha = 0.9;400}401}402403- (void)viewWillDisappear:(BOOL)animated {404[super viewWillDisappear:animated];405if (self.navigationController == nil) {406[self.presentingViewController performSelector:@selector(updatePreferenceChanges)];407}408}409410#pragma mark UITableView411412- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section {413if (section == 0) { // Add to general section414return [NSString stringWithFormat:@"PojavLauncher %@-%s (%s/%s)\n%@ on %@ (%s)\nPID: %d",415NSBundle.mainBundle.infoDictionary[@"CFBundleShortVersionString"],416CONFIG_TYPE, CONFIG_BRANCH, CONFIG_COMMIT,417UIDevice.currentDevice.completeOSVersion, [HostManager GetModelName], getenv("POJAV_DETECTEDINST"), getpid()];418}419420NSString *footer = NSLocalizedStringWithDefaultValue(([NSString stringWithFormat:@"preference.section.footer.%@", self.prefSections[section]]), @"Localizable", NSBundle.mainBundle, @" ", nil);421if ([footer isEqualToString:@" "]) {422return nil;423}424return footer;425}426427@end428429430