Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/PojavLauncher_iOS
Path: blob/main/Natives/LauncherProfilesViewController.m
589 views
1
#import "LauncherMenuViewController.h"
2
#import "LauncherNavigationController.h"
3
#import "LauncherPreferences.h"
4
#import "LauncherPrefGameDirViewController.h"
5
#import "LauncherPrefManageJREViewController.h"
6
#import "LauncherProfileEditorViewController.h"
7
#import "LauncherProfilesViewController.h"
8
//#import "NSFileManager+NRFileManager.h"
9
#import "PLProfiles.h"
10
#import "UIKit+AFNetworking.h"
11
#import "UIKit+hook.h"
12
#import "installer/FabricInstallViewController.h"
13
#import "installer/ForgeInstallViewController.h"
14
#import "installer/ModpackInstallViewController.h"
15
#import "ios_uikit_bridge.h"
16
#import "utils.h"
17
18
typedef NS_ENUM(NSUInteger, LauncherProfilesTableSection) {
19
kInstances,
20
kProfiles
21
};
22
23
@interface LauncherProfilesViewController () //<UIContextMenuInteractionDelegate>
24
25
@property(nonatomic) UIBarButtonItem *createButtonItem;
26
@end
27
28
@implementation LauncherProfilesViewController
29
30
- (id)init {
31
self = [super init];
32
self.title = localize(@"Profiles", nil);
33
return self;
34
}
35
36
- (NSString *)imageName {
37
return @"MenuProfiles";
38
}
39
40
- (void)viewDidLoad
41
{
42
[super viewDidLoad];
43
44
UIMenu *createMenu = [UIMenu menuWithTitle:localize(@"profile.title.create", nil) image:nil identifier:nil
45
options:UIMenuOptionsDisplayInline
46
children:@[
47
[UIAction
48
actionWithTitle:@"Vanilla" image:nil
49
identifier:@"vanilla" handler:^(UIAction *action) {
50
[self actionEditProfile:@{
51
@"name": @"",
52
@"lastVersionId": @"latest-release"}];
53
}],
54
#if 0 // TODO
55
[UIAction
56
actionWithTitle:@"OptiFine" image:nil
57
identifier:@"optifine" handler:createHandler],
58
#endif
59
[UIAction
60
actionWithTitle:@"Fabric/Quilt" image:nil
61
identifier:@"fabric_or_quilt" handler:^(UIAction *action) {
62
[self actionCreateFabricProfile];
63
}],
64
[UIAction
65
actionWithTitle:@"Forge" image:nil
66
identifier:@"forge" handler:^(UIAction *action) {
67
[self actionCreateForgeProfile];
68
}],
69
[UIAction
70
actionWithTitle:@"Modpack" image:nil
71
identifier:@"modpack" handler:^(UIAction *action) {
72
[self actionCreateModpackProfile];
73
}]
74
]];
75
self.createButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd menu:createMenu];
76
77
self.tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStyleInsetGrouped];
78
self.tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeInteractive;
79
}
80
81
- (void)viewWillAppear:(BOOL)animated {
82
[super viewWillAppear:animated];
83
84
// Put navigation buttons back in place
85
self.navigationItem.rightBarButtonItems = @[[sidebarViewController drawAccountButton], self.createButtonItem];
86
87
// Pickup changes made in the profile editor and switching instance
88
[PLProfiles updateCurrent];
89
[self.tableView reloadData];
90
[self.navigationController performSelector:@selector(reloadProfileList)];
91
}
92
93
- (void)actionTogglePrefIsolation:(UISwitch *)sender {
94
if (!sender.isOn) {
95
setPrefBool(@"internal.isolated", NO);
96
}
97
toggleIsolatedPref(sender.isOn);
98
}
99
100
- (void)actionCreateFabricProfile {
101
FabricInstallViewController *vc = [FabricInstallViewController new];
102
[self presentNavigatedViewController:vc];
103
}
104
105
- (void)actionCreateForgeProfile {
106
ForgeInstallViewController *vc = [ForgeInstallViewController new];
107
[self presentNavigatedViewController:vc];
108
}
109
110
- (void)actionCreateModpackProfile {
111
ModpackInstallViewController *vc = [ModpackInstallViewController new];
112
[self presentNavigatedViewController:vc];
113
}
114
115
- (void)actionEditProfile:(NSDictionary *)profile {
116
LauncherProfileEditorViewController *vc = [LauncherProfileEditorViewController new];
117
vc.profile = profile.mutableCopy;
118
[self presentNavigatedViewController:vc];
119
}
120
121
- (void)presentNavigatedViewController:(UIViewController *)vc {
122
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:vc];
123
//nav.navigationBar.prefersLargeTitles = YES;
124
[self presentViewController:nav animated:YES completion:nil];
125
}
126
127
#pragma mark Table view
128
129
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
130
return 2;
131
}
132
133
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
134
switch (section) {
135
case 0: return localize(@"profile.section.instance", nil);
136
case 1: return localize(@"profile.section.profiles", nil);
137
}
138
return nil;
139
}
140
141
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
142
switch (section) {
143
case 0: return 2;
144
case 1: return [PLProfiles.current.profiles count];
145
}
146
return 0;
147
}
148
149
- (void)setupInstanceCell:(UITableViewCell *) cell atRow:(NSInteger)row {
150
cell.userInteractionEnabled = !getenv("DEMO_LOCK");
151
if (row == 0) {
152
cell.imageView.image = [UIImage systemImageNamed:@"folder"];
153
cell.textLabel.text = localize(@"preference.title.game_directory", nil);
154
cell.detailTextLabel.text = getenv("DEMO_LOCK") ? @".demo" : getPrefObject(@"general.game_directory");
155
} else {
156
NSString *imageName;
157
if (@available(iOS 15.0, *)) {
158
imageName = @"folder.badge.gearshape";
159
} else {
160
imageName = @"folder.badge.gear";
161
}
162
cell.imageView.image = [UIImage systemImageNamed:imageName];
163
cell.textLabel.text = localize(@"profile.title.separate_preference", nil);
164
cell.detailTextLabel.text = localize(@"profile.detail.separate_preference", nil);
165
UISwitch *view = [UISwitch new];
166
[view setOn:getPrefBool(@"internal.isolated") animated:NO];
167
[view addTarget:self action:@selector(actionTogglePrefIsolation:) forControlEvents:UIControlEventValueChanged];
168
cell.accessoryView = view;
169
}
170
}
171
172
- (void)setupProfileCell:(UITableViewCell *) cell atRow:(NSInteger)row {
173
NSMutableDictionary *profile = PLProfiles.current.profiles.allValues[row];
174
175
cell.textLabel.text = profile[@"name"];
176
cell.detailTextLabel.text = profile[@"lastVersionId"];
177
cell.imageView.layer.magnificationFilter = kCAFilterNearest;
178
179
UIImage *fallbackImage = [[UIImage imageNamed:@"DefaultProfile"] _imageWithSize:CGSizeMake(40, 40)];
180
[cell.imageView setImageWithURL:[NSURL URLWithString:profile[@"icon"]] placeholderImage:fallbackImage];
181
}
182
183
- (UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
184
{
185
NSString *cellID = indexPath.section == kInstances ? @"InstanceCell" : @"ProfileCell";
186
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
187
if (cell == nil) {
188
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellID];
189
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
190
cell.detailTextLabel.numberOfLines = 0;
191
cell.detailTextLabel.lineBreakMode = NSLineBreakByWordWrapping;
192
if (indexPath.section == kProfiles) {
193
cell.imageView.frame = CGRectMake(0, 0, 40, 40);
194
cell.imageView.isSizeFixed = YES;
195
}
196
} else {
197
cell.imageView.image = nil;
198
cell.userInteractionEnabled = YES;
199
cell.accessoryView = nil;
200
}
201
202
if (indexPath.section == kInstances) {
203
[self setupInstanceCell:cell atRow:indexPath.row];
204
} else {
205
[self setupProfileCell:cell atRow:indexPath.row];
206
}
207
208
cell.textLabel.enabled = cell.detailTextLabel.enabled = cell.userInteractionEnabled;
209
return cell;
210
}
211
212
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
213
[tableView deselectRowAtIndexPath:indexPath animated:NO];
214
215
if (indexPath.section == kInstances) {
216
if (indexPath.row == 0) {
217
[self.navigationController pushViewController:[LauncherPrefGameDirViewController new] animated:YES];
218
}
219
return;
220
}
221
222
[self actionEditProfile:PLProfiles.current.profiles.allValues[indexPath.row]];
223
}
224
225
#pragma mark Context Menu configuration
226
227
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
228
{
229
if (editingStyle != UITableViewCellEditingStyleDelete) return;
230
231
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
232
NSString *title = localize(@"preference.title.confirm", nil);
233
// reusing the delete runtime message
234
NSString *message = [NSString stringWithFormat:localize(@"preference.title.confirm.delete_runtime", nil), cell.textLabel.text];
235
UIAlertController *confirmAlert = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleActionSheet];
236
confirmAlert.popoverPresentationController.sourceView = cell;
237
confirmAlert.popoverPresentationController.sourceRect = cell.bounds;
238
UIAlertAction *ok = [UIAlertAction actionWithTitle:localize(@"OK", nil) style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
239
[PLProfiles.current.profiles removeObjectForKey:cell.textLabel.text];
240
if ([PLProfiles.current.selectedProfileName isEqualToString:cell.textLabel.text]) {
241
// The one being deleted is the selected one, switch to the random one now
242
PLProfiles.current.selectedProfileName = PLProfiles.current.profiles.allKeys[0];
243
[self.navigationController performSelector:@selector(reloadProfileList)];
244
} else {
245
[PLProfiles.current save];
246
}
247
[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
248
}];
249
UIAlertAction *cancel = [UIAlertAction actionWithTitle:localize(@"Cancel", nil) style:UIAlertActionStyleCancel handler:nil];
250
[confirmAlert addAction:cancel];
251
[confirmAlert addAction:ok];
252
[self presentViewController:confirmAlert animated:YES completion:nil];
253
}
254
255
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
256
{
257
if (indexPath.section == kInstances || PLProfiles.current.profiles.count==1) {
258
return UITableViewCellEditingStyleNone;
259
}
260
return UITableViewCellEditingStyleDelete;
261
}
262
263
@end
264
265