Various iOS Ui improvements, especially on iOS 26
BIN
iOS/Assets.car
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 43 KiB |
After Width: | Height: | Size: 339 KiB |
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
After Width: | Height: | Size: 2.1 KiB |
|
@ -119,9 +119,17 @@
|
|||
[button sizeToFit];
|
||||
CGRect frame = button.frame;
|
||||
frame.size.width = ceil(frame.size.width + (label? 4 : 0));
|
||||
if (@available(iOS 19.0, *)) {
|
||||
if (label) {
|
||||
frame.size.width += 12;
|
||||
}
|
||||
}
|
||||
frame.size.height = 28;
|
||||
button.frame = frame;
|
||||
return [[UIBarButtonItem alloc] initWithCustomView:button];
|
||||
UIView *wrapper = [[UIView alloc] initWithFrame:button.bounds];
|
||||
[wrapper addSubview:button];
|
||||
UIBarButtonItem *item = [[UIBarButtonItem alloc] initWithCustomView:wrapper];
|
||||
return item;
|
||||
}
|
||||
return [[UIBarButtonItem alloc] initWithTitle:label style:UIBarButtonItemStylePlain target:target action:action];
|
||||
}
|
||||
|
@ -178,28 +186,37 @@
|
|||
hasSFSymbols = true;
|
||||
}
|
||||
|
||||
self.toolbarItems = @[
|
||||
hasSFSymbols?
|
||||
[self.class buttonWithLabel:nil
|
||||
imageWithName:@"square.and.arrow.up"
|
||||
target:self
|
||||
action:@selector(exportCheats)] :
|
||||
[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAction
|
||||
target:self
|
||||
action:@selector(exportCheats)],
|
||||
[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace
|
||||
target:nil
|
||||
action:NULL],
|
||||
[self.class buttonWithLabel:@"Import"
|
||||
imageWithName:@"square.and.arrow.down"
|
||||
UIBarButtonItem *export = hasSFSymbols?
|
||||
[self.class buttonWithLabel:nil
|
||||
imageWithName:@"square.and.arrow.up"
|
||||
target:self
|
||||
action:@selector(importCheats)],
|
||||
[self.class buttonWithLabel:@"Add"
|
||||
imageWithName:@"plus"
|
||||
target:self
|
||||
action:@selector(addCheat)],
|
||||
|
||||
];
|
||||
action:@selector(exportCheats)] :
|
||||
[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAction
|
||||
target:self
|
||||
action:@selector(exportCheats)];
|
||||
|
||||
UIBarButtonItem *flexItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace
|
||||
target:nil
|
||||
action:NULL];
|
||||
UIBarButtonItem *import = [self.class buttonWithLabel:@"Import"
|
||||
imageWithName:@"square.and.arrow.down"
|
||||
target:self
|
||||
action:@selector(importCheats)];
|
||||
|
||||
UIBarButtonItem *add = [self.class buttonWithLabel:@"Add"
|
||||
imageWithName:@"plus"
|
||||
target:self
|
||||
action:@selector(addCheat)];
|
||||
|
||||
if (@available(iOS 19.0, *)) {
|
||||
self.toolbarItems = @[export,
|
||||
flexItem,
|
||||
import, [UIBarButtonItem fixedSpaceItemOfWidth:0], add];
|
||||
} else {
|
||||
self.toolbarItems = @[export,
|
||||
flexItem,
|
||||
import, add];
|
||||
}
|
||||
|
||||
_gb = gb;
|
||||
return self;
|
||||
|
|
|
@ -283,7 +283,12 @@ static NSString *const tips[] = {
|
|||
button.backgroundColor = [UIColor colorWithWhite:0.5 alpha:0.3];
|
||||
button.layer.borderWidth = 2.0;
|
||||
button.layer.borderColor = [UIColor systemBlueColor].CGColor;
|
||||
button.layer.cornerRadius = 8.0;
|
||||
if (@available(iOS 19.0, *)) {
|
||||
button.layer.cornerRadius = 32.0;
|
||||
}
|
||||
else {
|
||||
button.layer.cornerRadius = 8.0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
button.backgroundColor = [UIColor clearColor];
|
||||
|
|
|
@ -247,8 +247,8 @@
|
|||
|
||||
if ([newName containsString:@"/"]) {
|
||||
[self.tableView reloadData];
|
||||
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"You can't use a name that contains “/”. Please choose another name."
|
||||
message:nil
|
||||
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Invalid Name"
|
||||
message:@"You can't use a name that contains “/”. Please choose another name."
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"OK"
|
||||
style:UIAlertActionStyleCancel
|
||||
|
|
|
@ -22,6 +22,7 @@ static NSString const *typeLightTemp = @"typeLightTemp";
|
|||
NSArray<NSDictionary *> *_structure;
|
||||
UINavigationController *_detailsNavigation;
|
||||
NSArray<NSArray<GBTheme *> *> *_themes; // For prewarming
|
||||
bool _iPadRoot;
|
||||
}
|
||||
|
||||
+ (UIImage *)settingsImageNamed:(NSString *)name
|
||||
|
@ -187,7 +188,7 @@ static NSString const *typeLightTemp = @"typeLightTemp";
|
|||
@{@"type": typeRadio, @"pref": @"GBFilter", @"title": @"HQ2x", @"value": @"HQ2x"},
|
||||
@{@"type": typeRadio, @"pref": @"GBFilter", @"title": @"OmniScale", @"value": @"OmniScale"},
|
||||
@{@"type": typeRadio, @"pref": @"GBFilter", @"title": @"OmniScale Legacy", @"value": @"OmniScaleLegacy"},
|
||||
@{@"type": typeRadio, @"pref": @"GBFilter", @"title": @"AA OmniScale Legacy", @"value": @"AAOmniScaleLegacy"},
|
||||
@{@"type": typeRadio, @"pref": @"GBFilter", @"title": @"Anti-aliased OmniScale Legacy", @"value": @"AAOmniScaleLegacy"},
|
||||
]
|
||||
},
|
||||
]
|
||||
|
@ -434,12 +435,20 @@ static NSString const *typeLightTemp = @"typeLightTemp";
|
|||
return controller;
|
||||
}
|
||||
|
||||
UISplitViewController *split = [[UISplitViewController alloc] init];
|
||||
UISplitViewController *split = nil;
|
||||
if (@available(iOS 14.5, *)) {
|
||||
split = [[UISplitViewController alloc] initWithStyle:UISplitViewControllerStyleDoubleColumn];
|
||||
split.displayModeButtonVisibility = UISplitViewControllerDisplayModeButtonVisibilityNever;
|
||||
}
|
||||
else {
|
||||
split = [[UISplitViewController alloc] init];
|
||||
}
|
||||
UIViewController *blank = [[UIViewController alloc] init];
|
||||
blank.view.backgroundColor = root.view.backgroundColor;
|
||||
root->_detailsNavigation = [[UINavigationController alloc] initWithRootViewController:blank];
|
||||
split.viewControllers = @[controller, root->_detailsNavigation];
|
||||
split.preferredDisplayMode = UISplitViewControllerDisplayModeAllVisible;
|
||||
root->_iPadRoot = true;
|
||||
return split;
|
||||
}
|
||||
|
||||
|
@ -729,7 +738,6 @@ static id ValueForItem(NSDictionary *item)
|
|||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
NSDictionary *item = [self itemForIndexPath:indexPath];
|
||||
|
||||
|
||||
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:nil];
|
||||
cell.textLabel.text = item[@"title"];
|
||||
|
@ -833,6 +841,13 @@ static id ValueForItem(NSDictionary *item)
|
|||
cell.separatorInset = UIEdgeInsetsZero;
|
||||
}
|
||||
cell.imageView.image = item[@"image"];
|
||||
if (@available(iOS 19.0, *)) {
|
||||
if (_iPadRoot) {
|
||||
cell.textLabel.textColor = [UIColor colorWithDynamicProvider:^UIColor *(UITraitCollection *traitCollection) {
|
||||
return cell.isSelected? [UIColor whiteColor] : [UIColor labelColor];
|
||||
}];
|
||||
}
|
||||
}
|
||||
return cell;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,11 +21,15 @@ static inline void temperature_tint(double temperature, double *r, double *g, do
|
|||
}
|
||||
|
||||
@implementation GBSlider
|
||||
{
|
||||
GBSliderStyle _style;
|
||||
}
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame
|
||||
{
|
||||
self = [super initWithFrame:frame];
|
||||
[self addTarget:self action:@selector(valueChanged) forControlEvents:UIControlEventValueChanged];
|
||||
self.style = GBSliderStyleTemperature;
|
||||
return self;
|
||||
}
|
||||
|
||||
|
@ -97,6 +101,10 @@ static inline void temperature_tint(double temperature, double *r, double *g, do
|
|||
|
||||
- (void)drawRect:(CGRect)rect
|
||||
{
|
||||
bool solarium = false;
|
||||
if (@available(iOS 19.0, *)) {
|
||||
solarium = true;
|
||||
}
|
||||
CGSize size = self.bounds.size;
|
||||
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(2, round(size.height / 2 - 1.5), size.width - 4, 3) cornerRadius:4];
|
||||
if (_style != GBSliderStyleHue) {
|
||||
|
@ -107,7 +115,7 @@ static inline void temperature_tint(double temperature, double *r, double *g, do
|
|||
[path appendPath:[UIBezierPath bezierPathWithRoundedRect:CGRectMake(size.width - 3, 12, 3, size.height - 24) cornerRadius:4]];
|
||||
}
|
||||
if (_style == GBSliderStyleHue) {
|
||||
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(3, round(size.height / 2 - 1.5) + 1, size.width - 6, 1) cornerRadius:4];
|
||||
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(3, round(size.height / 2 - 1.5) + 1 - solarium, size.width - 6, solarium? 2 : 1) cornerRadius:8];
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
CGContextSaveGState(context);
|
||||
[path addClip];
|
||||
|
@ -124,11 +132,12 @@ static inline void temperature_tint(double temperature, double *r, double *g, do
|
|||
};
|
||||
CFArrayRef colorsArray = CFArrayCreate(NULL, (const void **)colors, 7, &kCFTypeArrayCallBacks);
|
||||
CGGradientRef gradient = CGGradientCreateWithColors(colorspace, colorsArray, NULL);
|
||||
unsigned spacing = solarium? 16 : 3;
|
||||
CGContextDrawLinearGradient(context,
|
||||
gradient,
|
||||
(CGPoint){3, 0},
|
||||
(CGPoint){size.width - 3, 0},
|
||||
0);
|
||||
(CGPoint){spacing, 0},
|
||||
(CGPoint){size.width - spacing, 0},
|
||||
kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation);
|
||||
CFRelease(gradient);
|
||||
CFRelease(colorsArray);
|
||||
CFRelease(colorspace);
|
||||
|
@ -139,11 +148,44 @@ static inline void temperature_tint(double temperature, double *r, double *g, do
|
|||
green:120 / 255.0
|
||||
blue:130 / 255.0
|
||||
alpha:70 / 255.0] set];
|
||||
[path fill];
|
||||
if (!solarium) {
|
||||
[path fill];
|
||||
}
|
||||
|
||||
[super drawRect:rect];
|
||||
}
|
||||
|
||||
- (void)setStyle:(GBSliderStyle)style
|
||||
{
|
||||
_style = style;
|
||||
if (@available(iOS 26.0, *)) {
|
||||
switch (_style) {
|
||||
case GBSliderStyleTemperature:
|
||||
case GBSliderStyleTicks: {
|
||||
UISliderTrackConfiguration *conf = [UISliderTrackConfiguration configurationWithNumberOfTicks:3];
|
||||
conf.allowsTickValuesOnly = false;
|
||||
conf.neutralValue = 0.5;
|
||||
self.trackConfiguration = conf;
|
||||
self.maximumTrackTintColor = nil;
|
||||
self.minimumTrackTintColor = nil;
|
||||
break;
|
||||
}
|
||||
case GBSliderStyleHue: {
|
||||
UISliderTrackConfiguration *conf = [UISliderTrackConfiguration configurationWithNumberOfTicks:0];
|
||||
conf.allowsTickValuesOnly = false;
|
||||
self.trackConfiguration = conf;
|
||||
self.minimumTrackTintColor = [UIColor clearColor];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (GBSliderStyle)style
|
||||
{
|
||||
return _style;
|
||||
}
|
||||
|
||||
- (void)setFrame:(CGRect)frame
|
||||
{
|
||||
[super setFrame:frame];
|
||||
|
|
|
@ -39,8 +39,8 @@
|
|||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
self.view.bounds = CGRectMake(0, 0, 0x300, 0x300);
|
||||
UIView *root = self.view;
|
||||
UIView *root = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 0x300, 0x300)];
|
||||
[self.view addSubview:root];
|
||||
for (unsigned i = 0; i < 9; i++) {
|
||||
unsigned x = i % 3;
|
||||
unsigned y = i / 3;
|
||||
|
@ -114,6 +114,12 @@
|
|||
[self presentViewController:controller animated:true completion:nil];
|
||||
}
|
||||
|
||||
- (void)viewWillLayoutSubviews
|
||||
{
|
||||
[super viewWillLayoutSubviews];
|
||||
self.view.subviews.firstObject.frame = [self.view.safeAreaLayoutGuide layoutFrame];
|
||||
}
|
||||
|
||||
- (NSString *)title
|
||||
{
|
||||
return @"Save States";
|
||||
|
|
|
@ -65,8 +65,8 @@
|
|||
|
||||
- (void)showPopup
|
||||
{
|
||||
UIAlertController *alert = [UIAlertController alertControllerWithTitle:[NSString stringWithFormat:@"Apply “%@” as the current theme?", _verticalLayout.theme.name]
|
||||
message:nil
|
||||
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Apply Theme"
|
||||
message:[NSString stringWithFormat:@"Apply “%@” as the current theme?", _verticalLayout.theme.name]
|
||||
preferredStyle:[UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad?
|
||||
UIAlertControllerStyleAlert : UIAlertControllerStyleActionSheet];
|
||||
if (false) {
|
||||
|
|
|
@ -1814,8 +1814,8 @@ didReceiveNotificationResponse:(UNNotificationResponse *)response
|
|||
{
|
||||
UIAlertControllerStyle style = [UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad?
|
||||
UIAlertControllerStyleAlert : UIAlertControllerStyleActionSheet;
|
||||
GBCheckableAlertController *menu = [GBCheckableAlertController alertControllerWithTitle:@"Connect which accessory?"
|
||||
message:nil
|
||||
GBCheckableAlertController *menu = [GBCheckableAlertController alertControllerWithTitle:@"Connect Accessory"
|
||||
message:@"Choose an accessory to connect."
|
||||
preferredStyle:style];
|
||||
[menu addAction:[UIAlertAction actionWithTitle:@"None"
|
||||
style:UIAlertActionStyleDefault
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
<dict>
|
||||
<key>CFBundleTypeIconFiles</key>
|
||||
<array>
|
||||
<string>Cartridge64.png</string>
|
||||
<string>Cartridge.png</string>
|
||||
</array>
|
||||
<key>CFBundleTypeExtensions</key>
|
||||
|
@ -81,6 +82,7 @@
|
|||
<dict>
|
||||
<key>CFBundleTypeIconFiles</key>
|
||||
<array>
|
||||
<string>ColorCartridge64.png</string>
|
||||
<string>ColorCartridge.png</string>
|
||||
</array>
|
||||
<key>CFBundleTypeExtensions</key>
|
||||
|
@ -99,6 +101,7 @@
|
|||
<dict>
|
||||
<key>CFBundleTypeIconFiles</key>
|
||||
<array>
|
||||
<string>ColorCartridge64.png</string>
|
||||
<string>ColorCartridge.png</string>
|
||||
</array>
|
||||
<key>CFBundleTypeExtensions</key>
|
||||
|
@ -157,6 +160,12 @@
|
|||
<string>gb</string>
|
||||
</array>
|
||||
</dict>
|
||||
<key>UTTypeIconFiles</key>
|
||||
<array>
|
||||
<string>Cartridge64</string>
|
||||
<string>Cartridge</string>
|
||||
</array>
|
||||
|
||||
</dict>
|
||||
<dict>
|
||||
<key>UTTypeConformsTo</key>
|
||||
|
@ -174,6 +183,11 @@
|
|||
<string>gbc</string>
|
||||
</array>
|
||||
</dict>
|
||||
<key>UTTypeIconFiles</key>
|
||||
<array>
|
||||
<string>ColorCartridge64</string>
|
||||
<string>ColorCartridge</string>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>UTTypeConformsTo</key>
|
||||
|
@ -191,6 +205,11 @@
|
|||
<string>isx</string>
|
||||
</array>
|
||||
</dict>
|
||||
<key>UTTypeIconFiles</key>
|
||||
<array>
|
||||
<string>ColorCartridge64</string>
|
||||
<string>ColorCartridge</string>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>UTTypeConformsTo</key>
|
||||
|
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 37 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 62 KiB |
Before Width: | Height: | Size: 124 KiB After Width: | Height: | Size: 124 KiB |
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 6.8 KiB |
BIN
iOS/logo@2x.png
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
BIN
iOS/logo@3x.png
Before Width: | Height: | Size: 53 KiB After Width: | Height: | Size: 53 KiB |
|
@ -146,6 +146,9 @@ int main(int argc, char * argv[])
|
|||
@"Manual": @NO,
|
||||
},
|
||||
},
|
||||
|
||||
// Forces iOS to use Solarium even when linking against older SDKs
|
||||
@"com.apple.SwiftUI.IgnoreSolariumLinkedOnCheck": @YES,
|
||||
}];
|
||||
|
||||
if (![[defaults stringForKey:@"GBThemesVersion"] isEqualToString:@(GB_VERSION)]) {
|
||||
|
|
Before Width: | Height: | Size: 87 KiB After Width: | Height: | Size: 87 KiB |
Before Width: | Height: | Size: 188 KiB After Width: | Height: | Size: 188 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 38 KiB |