GTK: Start working on accounts UI and complete more menu entries
This commit is contained in:
parent
eb9601d6cf
commit
7284193981
|
@ -12,7 +12,7 @@ import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
public enum GtkEnvBackend implements LauncherEnv.EnvBackend { //TODO test
|
public enum GtkEnvBackend implements LauncherEnv.EnvBackend {
|
||||||
INSTANCE;
|
INSTANCE;
|
||||||
|
|
||||||
public Window dialogParent = null;
|
public Window dialogParent = null;
|
||||||
|
|
|
@ -3,6 +3,7 @@ package io.gitlab.jfronny.inceptum.gtk;
|
||||||
import io.gitlab.jfronny.inceptum.common.*;
|
import io.gitlab.jfronny.inceptum.common.*;
|
||||||
import io.gitlab.jfronny.inceptum.gtk.window.MainWindow;
|
import io.gitlab.jfronny.inceptum.gtk.window.MainWindow;
|
||||||
import io.gitlab.jfronny.inceptum.launcher.LauncherEnv;
|
import io.gitlab.jfronny.inceptum.launcher.LauncherEnv;
|
||||||
|
import io.gitlab.jfronny.inceptum.launcher.api.account.AccountManager;
|
||||||
import org.gtk.gio.ApplicationFlags;
|
import org.gtk.gio.ApplicationFlags;
|
||||||
import org.gtk.glib.GLib;
|
import org.gtk.glib.GLib;
|
||||||
import org.gtk.gtk.Application;
|
import org.gtk.gtk.Application;
|
||||||
|
@ -35,6 +36,8 @@ public class GtkMain {
|
||||||
|
|
||||||
public static int showGui(String[] args) {
|
public static int showGui(String[] args) {
|
||||||
return setupApplication(args, app -> {
|
return setupApplication(args, app -> {
|
||||||
|
//TODO update check
|
||||||
|
AccountManager.loadAccounts();
|
||||||
GtkMenubar.create(app);
|
GtkMenubar.create(app);
|
||||||
var window = new MainWindow(app);
|
var window = new MainWindow(app);
|
||||||
window.show();
|
window.show();
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
package io.gitlab.jfronny.inceptum.gtk;
|
package io.gitlab.jfronny.inceptum.gtk;
|
||||||
|
|
||||||
|
import io.gitlab.jfronny.commons.io.JFiles;
|
||||||
|
import io.gitlab.jfronny.inceptum.common.MetaHolder;
|
||||||
|
import io.gitlab.jfronny.inceptum.gtk.window.dialog.MicrosoftLoginDialog;
|
||||||
import io.gitlab.jfronny.inceptum.gtk.window.dialog.ProcessStateWatcherDialog;
|
import io.gitlab.jfronny.inceptum.gtk.window.dialog.ProcessStateWatcherDialog;
|
||||||
|
import io.gitlab.jfronny.inceptum.gtk.window.settings.launcher.LauncherSettingsWindow;
|
||||||
import io.gitlab.jfronny.inceptum.launcher.system.launch.*;
|
import io.gitlab.jfronny.inceptum.launcher.system.launch.*;
|
||||||
import io.gitlab.jfronny.inceptum.launcher.util.ProcessState;
|
import io.gitlab.jfronny.inceptum.launcher.util.ProcessState;
|
||||||
import org.gtk.gtk.Application;
|
import org.gtk.gtk.Application;
|
||||||
|
@ -29,13 +33,32 @@ public class GtkMenubar {
|
||||||
var file = menu.submenu("file");
|
var file = menu.submenu("file");
|
||||||
file.button("new", () -> new NewInstanceWindow(app).show());
|
file.button("new", () -> new NewInstanceWindow(app).show());
|
||||||
file.button("redownload", () -> {
|
file.button("redownload", () -> {
|
||||||
//TODO
|
ProcessState state = new ProcessState(3 + Steps.STEPS.size() * InstanceList.size(), "Initializing");
|
||||||
|
ProcessStateWatcherDialog.show(
|
||||||
|
GtkEnvBackend.INSTANCE.dialogParent,
|
||||||
|
"Reloading data",
|
||||||
|
"Could not execute refresh task",
|
||||||
|
state,
|
||||||
|
cancel -> {
|
||||||
|
state.incrementStep("Clearing cache directories");
|
||||||
|
JFiles.clearDirectory(MetaHolder.ASSETS_DIR);
|
||||||
|
JFiles.clearDirectory(MetaHolder.LIBRARIES_DIR, path -> !path.startsWith(MetaHolder.LIBRARIES_DIR.resolve("io/gitlab/jfronny")));
|
||||||
|
JFiles.clearDirectory(MetaHolder.NATIVES_DIR, path -> !path.startsWith(MetaHolder.NATIVES_DIR.resolve("forceload")));
|
||||||
|
JFiles.clearDirectory(MetaHolder.CACHE_DIR);
|
||||||
|
if (cancel.get()) return;
|
||||||
|
state.incrementStep("Reloading instance list");
|
||||||
|
InstanceList.reset();
|
||||||
|
InstanceList.forEach(instance -> {
|
||||||
|
if (cancel.get()) return;
|
||||||
|
Steps.reDownload(instance, state, cancel);
|
||||||
|
});
|
||||||
|
}, R::nop);
|
||||||
});
|
});
|
||||||
file.button("exit", app::quit);
|
file.button("exit", app::quit);
|
||||||
launchMenu = menu.submenu("launch");
|
launchMenu = menu.submenu("launch");
|
||||||
generateLaunchMenu();
|
generateLaunchMenu();
|
||||||
accountsMenu = menu.submenu("account");
|
accountsMenu = menu.submenu("account");
|
||||||
generateAccountsMenu();
|
generateAccountsMenu(app);
|
||||||
var help = menu.submenu("help");
|
var help = menu.submenu("help");
|
||||||
help.button("about", AboutWindow::createAndShow);
|
help.button("about", AboutWindow::createAndShow);
|
||||||
help.button("log", () -> {
|
help.button("log", () -> {
|
||||||
|
@ -58,17 +81,14 @@ public class GtkMenubar {
|
||||||
public static void launch(Instance instance, LaunchType launchType) {
|
public static void launch(Instance instance, LaunchType launchType) {
|
||||||
if (instance.isSetupLocked) {
|
if (instance.isSetupLocked) {
|
||||||
LauncherEnv.showError(I18n.get("instance.launch.locked.setup"), I18n.get("instance.launch.locked"));
|
LauncherEnv.showError(I18n.get("instance.launch.locked.setup"), I18n.get("instance.launch.locked"));
|
||||||
return;
|
} else if (instance.isRunningLocked) {
|
||||||
}
|
|
||||||
if (instance.isRunningLocked) {
|
|
||||||
LauncherEnv.showOkCancel(
|
LauncherEnv.showOkCancel(
|
||||||
I18n.get("instance.launch.locked.running"),
|
I18n.get("instance.launch.locked.running"),
|
||||||
I18n.get("instance.launch.locked"),
|
I18n.get("instance.launch.locked"),
|
||||||
() -> forceLaunch(instance, launchType),
|
() -> forceLaunch(instance, launchType),
|
||||||
R::nop
|
R::nop
|
||||||
);
|
);
|
||||||
}
|
} else forceLaunch(instance, launchType);
|
||||||
forceLaunch(instance, launchType);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void forceLaunch(Instance instance, LaunchType launchType) {
|
private static void forceLaunch(Instance instance, LaunchType launchType) {
|
||||||
|
@ -80,31 +100,31 @@ public class GtkMenubar {
|
||||||
state,
|
state,
|
||||||
cancel -> {
|
cancel -> {
|
||||||
try {
|
try {
|
||||||
Steps.reDownload(instance, Steps.createProcessState(), cancel);
|
Steps.reDownload(instance, state, cancel);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Utils.LOGGER.error("Could not fetch instance, trying to start anyways", e);
|
Utils.LOGGER.error("Could not fetch instance, trying to start anyways", e);
|
||||||
}
|
}
|
||||||
if (!cancel.get()) {
|
if (cancel.get()) return;
|
||||||
try {
|
state.updateStep("Starting Game");
|
||||||
if (launchType == LaunchType.Client) InstanceLauncher.launchClient(instance);
|
try {
|
||||||
else InstanceLauncher.launch(instance, launchType, false, AccountManager.NULL_AUTH);
|
if (launchType == LaunchType.Client) InstanceLauncher.launchClient(instance);
|
||||||
} catch (Throwable e) {
|
else InstanceLauncher.launch(instance, launchType, false, AccountManager.NULL_AUTH);
|
||||||
LauncherEnv.showError("Could not start instance", e);
|
} catch (Throwable e) {
|
||||||
}
|
LauncherEnv.showError("Could not start instance", e);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
R::nop
|
R::nop
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void generateAccountsMenu() {
|
public static void generateAccountsMenu(Application app) {
|
||||||
Objects.requireNonNull(accountsMenu);
|
Objects.requireNonNull(accountsMenu);
|
||||||
accountsMenu.clear();
|
accountsMenu.clear();
|
||||||
accountsMenu.button("new", () -> {
|
accountsMenu.button("new", () -> new MicrosoftLoginDialog(GtkEnvBackend.INSTANCE.dialogParent, null).show());
|
||||||
//TODO
|
|
||||||
});
|
|
||||||
accountsMenu.button("manage", () -> {
|
accountsMenu.button("manage", () -> {
|
||||||
//TODO UI to add/remove accounts
|
var window = new LauncherSettingsWindow(app);
|
||||||
|
window.activePage = "settings.accounts";
|
||||||
|
window.show();
|
||||||
});
|
});
|
||||||
List<MicrosoftAccount> accounts = new ArrayList<>(AccountManager.accounts);
|
List<MicrosoftAccount> accounts = new ArrayList<>(AccountManager.accounts);
|
||||||
accounts.add(null);
|
accounts.add(null);
|
||||||
|
|
|
@ -9,7 +9,7 @@ import io.gitlab.jfronny.inceptum.gtk.GtkMenubar;
|
||||||
import io.gitlab.jfronny.inceptum.gtk.menu.MenuBuilder;
|
import io.gitlab.jfronny.inceptum.gtk.menu.MenuBuilder;
|
||||||
import io.gitlab.jfronny.inceptum.gtk.util.I18n;
|
import io.gitlab.jfronny.inceptum.gtk.util.I18n;
|
||||||
import io.gitlab.jfronny.inceptum.gtk.util.ListIndexItem;
|
import io.gitlab.jfronny.inceptum.gtk.util.ListIndexItem;
|
||||||
import io.gitlab.jfronny.inceptum.gtk.window.InstanceSettingsWindow;
|
import io.gitlab.jfronny.inceptum.gtk.window.settings.instance.InstanceSettingsWindow;
|
||||||
import io.gitlab.jfronny.inceptum.launcher.LauncherEnv;
|
import io.gitlab.jfronny.inceptum.launcher.LauncherEnv;
|
||||||
import io.gitlab.jfronny.inceptum.launcher.system.instance.Instance;
|
import io.gitlab.jfronny.inceptum.launcher.system.instance.Instance;
|
||||||
import io.gitlab.jfronny.inceptum.launcher.system.instance.InstanceNameTool;
|
import io.gitlab.jfronny.inceptum.launcher.system.instance.InstanceNameTool;
|
||||||
|
@ -79,6 +79,14 @@ public class InstanceListEntryFactory extends SignalListItemFactory {
|
||||||
|
|
||||||
var menuBuilder = new MenuBuilder(li.popoverMenu, li.instance.id);
|
var menuBuilder = new MenuBuilder(li.popoverMenu, li.instance.id);
|
||||||
var launchSection = menuBuilder.literalSection("launch", null);
|
var launchSection = menuBuilder.literalSection("launch", null);
|
||||||
|
var kill = launchSection.literalButton("kill", I18n.get("instance.kill"), () -> {
|
||||||
|
//TODO test
|
||||||
|
LauncherEnv.showOkCancel(I18n.get("instance.kill.prompt"), I18n.get("instance.kill.details"), () -> {
|
||||||
|
if (!li.instance.kill()) LauncherEnv.showError(I18n.get("instance.kill.fail"), I18n.get("failed"));
|
||||||
|
}, R::nop);
|
||||||
|
});
|
||||||
|
kill.enabled = li.instance.isRunningLocked;
|
||||||
|
|
||||||
launchSection.literalButton("launch.client", I18n.get("instance.launch.client"),
|
launchSection.literalButton("launch.client", I18n.get("instance.launch.client"),
|
||||||
() -> GtkMenubar.launch(li.instance, LaunchType.Client))
|
() -> GtkMenubar.launch(li.instance, LaunchType.Client))
|
||||||
.iconName = "media-playback-start-symbolic";
|
.iconName = "media-playback-start-symbolic";
|
||||||
|
@ -98,7 +106,7 @@ public class InstanceListEntryFactory extends SignalListItemFactory {
|
||||||
try {
|
try {
|
||||||
JFiles.copyRecursive(li.instance.path, MetaHolder.INSTANCE_DIR.resolve(InstanceNameTool.getNextValid(s)));
|
JFiles.copyRecursive(li.instance.path, MetaHolder.INSTANCE_DIR.resolve(InstanceNameTool.getNextValid(s)));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
LauncherEnv.showError("Could not copy instance", e);
|
LauncherEnv.showError(I18n.get("instance.copy.fail"), e);
|
||||||
}
|
}
|
||||||
}, R::nop);
|
}, R::nop);
|
||||||
}).iconName = "edit-copy-symbolic";
|
}).iconName = "edit-copy-symbolic";
|
||||||
|
@ -107,13 +115,11 @@ public class InstanceListEntryFactory extends SignalListItemFactory {
|
||||||
try {
|
try {
|
||||||
JFiles.deleteRecursive(li.instance.path);
|
JFiles.deleteRecursive(li.instance.path);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
LauncherEnv.showError("Could not delete the instance", e);
|
LauncherEnv.showError(I18n.get("instance.delete.fail"), e);
|
||||||
}
|
}
|
||||||
}, R::nop);
|
}, R::nop);
|
||||||
}).iconName = "edit-delete-symbolic";
|
}).iconName = "edit-delete-symbolic";
|
||||||
|
|
||||||
//TODO kill current instance
|
|
||||||
|
|
||||||
Consumer<Signal<?>> dc = s -> toDisconnect.computeIfAbsent(li.instance.id, $ -> new HashSet<>()).add(s);
|
Consumer<Signal<?>> dc = s -> toDisconnect.computeIfAbsent(li.instance.id, $ -> new HashSet<>()).add(s);
|
||||||
|
|
||||||
dc.accept(li.launch.onClicked(() -> GtkMenubar.launch(li.instance, LaunchType.Client)));
|
dc.accept(li.launch.onClicked(() -> GtkMenubar.launch(li.instance, LaunchType.Client)));
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package io.gitlab.jfronny.inceptum.gtk.control;
|
package io.gitlab.jfronny.inceptum.gtk.control.settings;
|
||||||
|
|
||||||
|
import io.gitlab.jfronny.inceptum.gtk.control.ILabel;
|
||||||
import io.gitlab.jfronny.inceptum.gtk.util.I18n;
|
import io.gitlab.jfronny.inceptum.gtk.util.I18n;
|
||||||
import org.gtk.gtk.*;
|
import org.gtk.gtk.*;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
|
@ -1,23 +1,20 @@
|
||||||
package io.gitlab.jfronny.inceptum.gtk.window.edit;
|
package io.gitlab.jfronny.inceptum.gtk.control.settings;
|
||||||
|
|
||||||
import io.gitlab.jfronny.commons.StringFormatter;
|
import io.gitlab.jfronny.commons.StringFormatter;
|
||||||
import io.gitlab.jfronny.inceptum.gtk.GtkEnvBackend;
|
import io.gitlab.jfronny.inceptum.gtk.GtkEnvBackend;
|
||||||
import io.gitlab.jfronny.inceptum.gtk.control.ILabel;
|
import io.gitlab.jfronny.inceptum.gtk.control.ILabel;
|
||||||
import io.gitlab.jfronny.inceptum.gtk.control.IRow;
|
import io.gitlab.jfronny.inceptum.gtk.control.settings.IRow;
|
||||||
import io.gitlab.jfronny.inceptum.gtk.util.I18n;
|
import io.gitlab.jfronny.inceptum.gtk.util.I18n;
|
||||||
import io.gitlab.jfronny.inceptum.gtk.window.InstanceSettingsWindow;
|
|
||||||
import io.gitlab.jfronny.inceptum.launcher.system.instance.Instance;
|
import io.gitlab.jfronny.inceptum.launcher.system.instance.Instance;
|
||||||
import org.gtk.gtk.*;
|
import org.gtk.gtk.*;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.annotations.PropertyKey;
|
import org.jetbrains.annotations.PropertyKey;
|
||||||
|
|
||||||
public class SettingsTab extends Box {
|
public class SettingsTab extends Box {
|
||||||
protected final Instance instance;
|
protected final Window window;
|
||||||
protected final InstanceSettingsWindow window;
|
|
||||||
|
|
||||||
public SettingsTab(Instance instance, InstanceSettingsWindow window) {
|
public SettingsTab(Window window) {
|
||||||
super(Orientation.VERTICAL, 8);
|
super(Orientation.VERTICAL, 8);
|
||||||
this.instance = instance;
|
|
||||||
this.marginHorizontal = 24;
|
this.marginHorizontal = 24;
|
||||||
this.marginTop = 12;
|
this.marginTop = 12;
|
||||||
this.window = window;
|
this.window = window;
|
|
@ -1,20 +1,21 @@
|
||||||
package io.gitlab.jfronny.inceptum.gtk.window;
|
package io.gitlab.jfronny.inceptum.gtk.control.settings;
|
||||||
|
|
||||||
import io.gitlab.jfronny.inceptum.gtk.util.I18n;
|
import io.gitlab.jfronny.inceptum.gtk.util.I18n;
|
||||||
import io.gitlab.jfronny.inceptum.gtk.window.edit.*;
|
|
||||||
import io.gitlab.jfronny.inceptum.launcher.system.instance.Instance;
|
|
||||||
import org.gnome.adw.HeaderBar;
|
|
||||||
import org.gnome.adw.*;
|
import org.gnome.adw.*;
|
||||||
|
import org.gnome.adw.HeaderBar;
|
||||||
import org.gtk.gobject.BindingFlags;
|
import org.gtk.gobject.BindingFlags;
|
||||||
|
import org.gtk.gtk.*;
|
||||||
import org.gtk.gtk.Application;
|
import org.gtk.gtk.Application;
|
||||||
import org.gtk.gtk.Window;
|
import org.gtk.gtk.Window;
|
||||||
import org.gtk.gtk.*;
|
import org.jetbrains.annotations.PropertyKey;
|
||||||
|
|
||||||
public class InstanceSettingsWindow extends Window {
|
public class SettingsWindow extends Window {
|
||||||
public InstanceSettingsWindow(Application app, Instance instance) {
|
protected final ViewStack stack;
|
||||||
|
|
||||||
|
public SettingsWindow(Application app) {
|
||||||
this.application = app;
|
this.application = app;
|
||||||
|
|
||||||
ViewStack stack = new ViewStack();
|
this.stack = new ViewStack();
|
||||||
|
|
||||||
HeaderBar header = new HeaderBar();
|
HeaderBar header = new HeaderBar();
|
||||||
ViewSwitcherTitle viewSwitcher = new ViewSwitcherTitle();
|
ViewSwitcherTitle viewSwitcher = new ViewSwitcherTitle();
|
||||||
|
@ -35,9 +36,13 @@ public class InstanceSettingsWindow extends Window {
|
||||||
view.append(bottomBar);
|
view.append(bottomBar);
|
||||||
|
|
||||||
child = view;
|
child = view;
|
||||||
|
}
|
||||||
|
|
||||||
stack.addTitledWithIcon(new GeneralTab(instance, this), null, I18n.get("instance.settings.general"), "preferences-other-symbolic");
|
public void addTab(SettingsTab tab, @PropertyKey(resourceBundle = I18n.BUNDLE) String title, String iconName) {
|
||||||
stack.addTitledWithIcon(new ModsTab(instance, this), null, I18n.get("instance.settings.mods"), "package-x-generic-symbolic");
|
stack.addTitledWithIcon(tab, title, I18n.get(title), iconName);
|
||||||
stack.addTitledWithIcon(new ExportTab(instance, this), null, I18n.get("instance.settings.export"), "send-to-symbolic");
|
}
|
||||||
|
|
||||||
|
public void setActivePage(@PropertyKey(resourceBundle = I18n.BUNDLE) String title) {
|
||||||
|
stack.visibleChildName = title;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,49 +0,0 @@
|
||||||
package io.gitlab.jfronny.inceptum.gtk.window;
|
|
||||||
|
|
||||||
import io.gitlab.jfronny.inceptum.common.InceptumConfig;
|
|
||||||
import io.gitlab.jfronny.inceptum.common.model.inceptum.UpdateChannel;
|
|
||||||
import io.gitlab.jfronny.inceptum.gtk.control.IRow;
|
|
||||||
import org.gtk.gtk.*;
|
|
||||||
|
|
||||||
public class LauncherSettingsWindow extends Window {
|
|
||||||
public LauncherSettingsWindow(Application app) {
|
|
||||||
this.application = app;
|
|
||||||
|
|
||||||
var box = new Box(Orientation.VERTICAL, 8);
|
|
||||||
box.marginHorizontal = 24;
|
|
||||||
box.marginTop = 12;
|
|
||||||
this.child = box;
|
|
||||||
|
|
||||||
{
|
|
||||||
Frame frame = new Frame(null);
|
|
||||||
ListBox listBox = new ListBox();
|
|
||||||
listBox.selectionMode = SelectionMode.NONE;
|
|
||||||
frame.child = listBox;
|
|
||||||
box.append(frame);
|
|
||||||
{
|
|
||||||
IRow row = new IRow("settings.snapshots", "settings.snapshots.subtitle");
|
|
||||||
listBox.append(row);
|
|
||||||
row.setSwitch(InceptumConfig.snapshots, b -> {
|
|
||||||
InceptumConfig.snapshots = b;
|
|
||||||
InceptumConfig.saveConfig();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
{
|
|
||||||
IRow row = new IRow("settings.update-channel", "settings.update-channel.subtitle");
|
|
||||||
listBox.append(row);
|
|
||||||
row.setDropdown(new String[] {"Stable", "CI"}, InceptumConfig.channel == UpdateChannel.CI ? 1 : 0, state -> {
|
|
||||||
InceptumConfig.channel = state == 1 ? UpdateChannel.CI : UpdateChannel.Stable;
|
|
||||||
InceptumConfig.saveConfig();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
{
|
|
||||||
IRow row = new IRow("settings.author-name", "settings.author-name.subtitle");
|
|
||||||
listBox.append(row);
|
|
||||||
row.setEntry(InceptumConfig.authorName, s -> {
|
|
||||||
InceptumConfig.authorName = s;
|
|
||||||
InceptumConfig.saveConfig();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -8,6 +8,7 @@ import io.gitlab.jfronny.inceptum.gtk.control.InstanceListEntryFactory;
|
||||||
import io.gitlab.jfronny.inceptum.gtk.menu.MenuBuilder;
|
import io.gitlab.jfronny.inceptum.gtk.menu.MenuBuilder;
|
||||||
import io.gitlab.jfronny.inceptum.gtk.util.I18n;
|
import io.gitlab.jfronny.inceptum.gtk.util.I18n;
|
||||||
import io.gitlab.jfronny.inceptum.gtk.util.ListIndexModel;
|
import io.gitlab.jfronny.inceptum.gtk.util.ListIndexModel;
|
||||||
|
import io.gitlab.jfronny.inceptum.gtk.window.settings.launcher.LauncherSettingsWindow;
|
||||||
import io.gitlab.jfronny.inceptum.launcher.system.instance.*;
|
import io.gitlab.jfronny.inceptum.launcher.system.instance.*;
|
||||||
import io.gitlab.jfronny.inceptum.launcher.system.launch.LaunchType;
|
import io.gitlab.jfronny.inceptum.launcher.system.launch.LaunchType;
|
||||||
import org.gnome.adw.Clamp;
|
import org.gnome.adw.Clamp;
|
||||||
|
@ -75,9 +76,9 @@ public class MainWindow extends ApplicationWindow {
|
||||||
|
|
||||||
instanceList = new ArrayList<>();
|
instanceList = new ArrayList<>();
|
||||||
instanceListIndex = new ListIndexModel(instanceList.size());
|
instanceListIndex = new ListIndexModel(instanceList.size());
|
||||||
var singleSelection = new NoSelection(instanceListIndex);
|
var selection = new NoSelection(instanceListIndex);
|
||||||
|
|
||||||
ListView listView = new ListView(singleSelection, new InstanceListEntryFactory(app, instanceList));
|
ListView listView = new ListView(selection, new InstanceListEntryFactory(app, instanceList));
|
||||||
listView.addCssClass("rich-list");
|
listView.addCssClass("rich-list");
|
||||||
listView.showSeparators = true;
|
listView.showSeparators = true;
|
||||||
listView.onActivate(position -> {
|
listView.onActivate(position -> {
|
||||||
|
@ -92,7 +93,7 @@ public class MainWindow extends ApplicationWindow {
|
||||||
listContainer = new Clamp();
|
listContainer = new Clamp();
|
||||||
listContainer.maximumSize = 900;
|
listContainer.maximumSize = 900;
|
||||||
listContainer.child = frame;
|
listContainer.child = frame;
|
||||||
gridView = new GridView(singleSelection, new InstanceGridEntryFactory(instanceList));
|
gridView = new GridView(selection, new InstanceGridEntryFactory(instanceList));
|
||||||
empty = new StatusPage();
|
empty = new StatusPage();
|
||||||
empty.title = I18n.get("main.empty.title");
|
empty.title = I18n.get("main.empty.title");
|
||||||
empty.description = I18n.get("main.empty.description");
|
empty.description = I18n.get("main.empty.description");
|
||||||
|
@ -106,7 +107,7 @@ public class MainWindow extends ApplicationWindow {
|
||||||
scroll.setPolicy(PolicyType.NEVER, PolicyType.AUTOMATIC);
|
scroll.setPolicy(PolicyType.NEVER, PolicyType.AUTOMATIC);
|
||||||
scroll.child = stack;
|
scroll.child = stack;
|
||||||
|
|
||||||
setDefaultSize(360, 720);
|
setDefaultSize(720, 360);
|
||||||
title = "Inceptum";
|
title = "Inceptum";
|
||||||
titlebar = header;
|
titlebar = header;
|
||||||
showMenubar = false;
|
showMenubar = false;
|
||||||
|
|
|
@ -16,7 +16,7 @@ public class MicrosoftLoginDialog extends MessageDialog {
|
||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MicrosoftLoginDialog(@Nullable Window parent, MicrosoftAccount account) {
|
public MicrosoftLoginDialog(@Nullable Window parent, @Nullable MicrosoftAccount account) {
|
||||||
super(
|
super(
|
||||||
parent,
|
parent,
|
||||||
flags(parent != null),
|
flags(parent != null),
|
||||||
|
@ -25,6 +25,13 @@ public class MicrosoftLoginDialog extends MessageDialog {
|
||||||
I18n.get("auth.description")
|
I18n.get("auth.description")
|
||||||
);
|
);
|
||||||
title = I18n.get("auth.title");
|
title = I18n.get("auth.title");
|
||||||
|
onResponse(responseId -> {
|
||||||
|
switch (ResponseType.of(responseId)) {
|
||||||
|
case CLOSE, CANCEL -> this.close();
|
||||||
|
case DELETE_EVENT -> this.destroy();
|
||||||
|
default -> Utils.LOGGER.error("Unexpected response type: " + responseId);
|
||||||
|
}
|
||||||
|
});
|
||||||
var btn = Button.newWithLabel(I18n.get("auth.open-browser"));
|
var btn = Button.newWithLabel(I18n.get("auth.open-browser"));
|
||||||
((Box) messageArea).append(btn);
|
((Box) messageArea).append(btn);
|
||||||
btn.onClicked(() -> {
|
btn.onClicked(() -> {
|
||||||
|
|
|
@ -28,6 +28,8 @@ public class ProcessStateWatcherDialog extends MessageDialog {
|
||||||
}
|
}
|
||||||
|
|
||||||
public ProcessStateWatcherDialog(Window parent, String title, String errorMessage, ProcessState state, ThrowingConsumer<AtomicBoolean, ?> executor, @Nullable Runnable cancel) {
|
public ProcessStateWatcherDialog(Window parent, String title, String errorMessage, ProcessState state, ThrowingConsumer<AtomicBoolean, ?> executor, @Nullable Runnable cancel) {
|
||||||
|
//TODO alternate UI: Only show progress bar by default, but have a dropdown to a "console" with the actual steps
|
||||||
|
// this should make visualizing parallelized steps easier
|
||||||
super(parent, DialogFlags.MODAL.or(DialogFlags.DESTROY_WITH_PARENT), MessageType.INFO, ButtonsType.NONE, null);
|
super(parent, DialogFlags.MODAL.or(DialogFlags.DESTROY_WITH_PARENT), MessageType.INFO, ButtonsType.NONE, null);
|
||||||
this.state = state;
|
this.state = state;
|
||||||
this.cancel = cancel;
|
this.cancel = cancel;
|
||||||
|
@ -61,7 +63,7 @@ public class ProcessStateWatcherDialog extends MessageDialog {
|
||||||
if (!nc.equals(cachedState)) {
|
if (!nc.equals(cachedState)) {
|
||||||
cachedState = nc;
|
cachedState = nc;
|
||||||
setMarkup(cachedState.msg);
|
setMarkup(cachedState.msg);
|
||||||
progress.fraction = cachedState.progress;
|
progress.fraction = Math.min(cachedState.progress, 1);
|
||||||
widget.queueDraw();
|
widget.queueDraw();
|
||||||
}
|
}
|
||||||
return GLib.SOURCE_CONTINUE;
|
return GLib.SOURCE_CONTINUE;
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
package io.gitlab.jfronny.inceptum.gtk.window.edit;
|
package io.gitlab.jfronny.inceptum.gtk.window.settings.instance;
|
||||||
|
|
||||||
import io.gitlab.jfronny.commons.ref.R;
|
import io.gitlab.jfronny.commons.ref.R;
|
||||||
import io.gitlab.jfronny.inceptum.common.Utils;
|
import io.gitlab.jfronny.inceptum.common.Utils;
|
||||||
import io.gitlab.jfronny.inceptum.gtk.GtkEnvBackend;
|
import io.gitlab.jfronny.inceptum.gtk.GtkEnvBackend;
|
||||||
import io.gitlab.jfronny.inceptum.gtk.GtkMain;
|
import io.gitlab.jfronny.inceptum.gtk.GtkMain;
|
||||||
|
import io.gitlab.jfronny.inceptum.gtk.control.settings.SettingsTab;
|
||||||
import io.gitlab.jfronny.inceptum.gtk.util.I18n;
|
import io.gitlab.jfronny.inceptum.gtk.util.I18n;
|
||||||
import io.gitlab.jfronny.inceptum.gtk.window.InstanceSettingsWindow;
|
|
||||||
import io.gitlab.jfronny.inceptum.gtk.window.dialog.ProcessStateWatcherDialog;
|
import io.gitlab.jfronny.inceptum.gtk.window.dialog.ProcessStateWatcherDialog;
|
||||||
import io.gitlab.jfronny.inceptum.launcher.system.exporter.Exporter;
|
import io.gitlab.jfronny.inceptum.launcher.system.exporter.Exporter;
|
||||||
import io.gitlab.jfronny.inceptum.launcher.system.exporter.Exporters;
|
import io.gitlab.jfronny.inceptum.launcher.system.exporter.Exporters;
|
||||||
|
@ -16,8 +16,11 @@ import org.gtk.gtk.*;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
|
||||||
public class ExportTab extends SettingsTab {
|
public class ExportTab extends SettingsTab {
|
||||||
|
private final Instance instance;
|
||||||
|
|
||||||
public ExportTab(Instance instance, InstanceSettingsWindow window) {
|
public ExportTab(Instance instance, InstanceSettingsWindow window) {
|
||||||
super(instance, window);
|
super(window);
|
||||||
|
this.instance = instance;
|
||||||
section(null, section -> {
|
section(null, section -> {
|
||||||
{
|
{
|
||||||
var row = section.row("instance.settings.export.version", "instance.settings.export.version.subtitle");
|
var row = section.row("instance.settings.export.version", "instance.settings.export.version.subtitle");
|
|
@ -1,13 +1,13 @@
|
||||||
package io.gitlab.jfronny.inceptum.gtk.window.edit;
|
package io.gitlab.jfronny.inceptum.gtk.window.settings.instance;
|
||||||
|
|
||||||
import io.github.jwharm.javagi.GErrorException;
|
import io.github.jwharm.javagi.GErrorException;
|
||||||
import io.gitlab.jfronny.commons.ArgumentsTokenizer;
|
import io.gitlab.jfronny.commons.ArgumentsTokenizer;
|
||||||
import io.gitlab.jfronny.commons.io.JFiles;
|
import io.gitlab.jfronny.commons.io.JFiles;
|
||||||
import io.gitlab.jfronny.inceptum.common.*;
|
import io.gitlab.jfronny.inceptum.common.*;
|
||||||
import io.gitlab.jfronny.inceptum.gtk.control.ILabel;
|
import io.gitlab.jfronny.inceptum.gtk.control.ILabel;
|
||||||
|
import io.gitlab.jfronny.inceptum.gtk.control.settings.SettingsTab;
|
||||||
import io.gitlab.jfronny.inceptum.gtk.util.I18n;
|
import io.gitlab.jfronny.inceptum.gtk.util.I18n;
|
||||||
import io.gitlab.jfronny.inceptum.gtk.util.Memory;
|
import io.gitlab.jfronny.inceptum.gtk.util.Memory;
|
||||||
import io.gitlab.jfronny.inceptum.gtk.window.InstanceSettingsWindow;
|
|
||||||
import io.gitlab.jfronny.inceptum.launcher.api.FabricMetaApi;
|
import io.gitlab.jfronny.inceptum.launcher.api.FabricMetaApi;
|
||||||
import io.gitlab.jfronny.inceptum.launcher.api.McApi;
|
import io.gitlab.jfronny.inceptum.launcher.api.McApi;
|
||||||
import io.gitlab.jfronny.inceptum.launcher.model.fabric.FabricVersionLoaderInfo;
|
import io.gitlab.jfronny.inceptum.launcher.model.fabric.FabricVersionLoaderInfo;
|
||||||
|
@ -29,7 +29,7 @@ public class GeneralTab extends SettingsTab {
|
||||||
private static final VersionsList VERSIONS = McApi.getVersions();
|
private static final VersionsList VERSIONS = McApi.getVersions();
|
||||||
|
|
||||||
public GeneralTab(Instance instance, InstanceSettingsWindow window) {
|
public GeneralTab(Instance instance, InstanceSettingsWindow window) {
|
||||||
super(instance, window);
|
super(window);
|
||||||
section(null, section -> {
|
section(null, section -> {
|
||||||
var row = section.row("instance.settings.general.name", "instance.settings.general.name.placeholder");
|
var row = section.row("instance.settings.general.name", "instance.settings.general.name.placeholder");
|
||||||
Button apply = Button.newWithLabel(I18n.get("instance.settings.apply"));
|
Button apply = Button.newWithLabel(I18n.get("instance.settings.apply"));
|
||||||
|
@ -210,7 +210,7 @@ public class GeneralTab extends SettingsTab {
|
||||||
dialog.close();
|
dialog.close();
|
||||||
window.close();
|
window.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
showError("Could not delete the instance", e);
|
showError(I18n.get("instance.delete.fail"), e);
|
||||||
}
|
}
|
||||||
dialog.close();
|
dialog.close();
|
||||||
}
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
package io.gitlab.jfronny.inceptum.gtk.window.settings.instance;
|
||||||
|
|
||||||
|
import io.gitlab.jfronny.inceptum.gtk.control.settings.SettingsWindow;
|
||||||
|
import io.gitlab.jfronny.inceptum.launcher.system.instance.Instance;
|
||||||
|
import org.gtk.gtk.Application;
|
||||||
|
|
||||||
|
public class InstanceSettingsWindow extends SettingsWindow {
|
||||||
|
public InstanceSettingsWindow(Application app, Instance instance) {
|
||||||
|
super(app);
|
||||||
|
addTab(new GeneralTab(instance, this), "instance.settings.general", "preferences-other-symbolic");
|
||||||
|
addTab(new ModsTab(instance, this), "instance.settings.mods", "package-x-generic-symbolic");
|
||||||
|
addTab(new ExportTab(instance, this), "instance.settings.export", "send-to-symbolic");
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,12 +1,12 @@
|
||||||
package io.gitlab.jfronny.inceptum.gtk.window.edit;
|
package io.gitlab.jfronny.inceptum.gtk.window.settings.instance;
|
||||||
|
|
||||||
import io.gitlab.jfronny.inceptum.gtk.control.ILabel;
|
import io.gitlab.jfronny.inceptum.gtk.control.ILabel;
|
||||||
import io.gitlab.jfronny.inceptum.gtk.window.InstanceSettingsWindow;
|
import io.gitlab.jfronny.inceptum.gtk.control.settings.SettingsTab;
|
||||||
import io.gitlab.jfronny.inceptum.launcher.system.instance.Instance;
|
import io.gitlab.jfronny.inceptum.launcher.system.instance.Instance;
|
||||||
|
|
||||||
public class ModsTab extends SettingsTab {
|
public class ModsTab extends SettingsTab {
|
||||||
public ModsTab(Instance instance, InstanceSettingsWindow window) {
|
public ModsTab(Instance instance, InstanceSettingsWindow window) {
|
||||||
super(instance, window);
|
super(window);
|
||||||
append(new ILabel("instance.settings.mods.unsupported"));
|
append(new ILabel("instance.settings.mods.unsupported"));
|
||||||
//TODO implement this, somehow
|
//TODO implement this, somehow
|
||||||
}
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
package io.gitlab.jfronny.inceptum.gtk.window.settings.launcher;
|
||||||
|
|
||||||
|
import io.gitlab.jfronny.inceptum.gtk.control.settings.SettingsTab;
|
||||||
|
import org.gtk.gtk.Label;
|
||||||
|
import org.gtk.gtk.Window;
|
||||||
|
|
||||||
|
public class AccountsTab extends SettingsTab {
|
||||||
|
public AccountsTab(Window window) {
|
||||||
|
super(window);
|
||||||
|
append(new Label("Account management is still in development"));
|
||||||
|
//TODO implement
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
package io.gitlab.jfronny.inceptum.gtk.window.settings.launcher;
|
||||||
|
|
||||||
|
import io.gitlab.jfronny.inceptum.common.InceptumConfig;
|
||||||
|
import io.gitlab.jfronny.inceptum.common.model.inceptum.UpdateChannel;
|
||||||
|
import io.gitlab.jfronny.inceptum.gtk.control.settings.IRow;
|
||||||
|
import io.gitlab.jfronny.inceptum.gtk.control.settings.SettingsTab;
|
||||||
|
import org.gtk.gtk.Window;
|
||||||
|
|
||||||
|
public class GeneralTab extends SettingsTab {
|
||||||
|
public GeneralTab(Window window) {
|
||||||
|
super(window);
|
||||||
|
section(null, section -> {
|
||||||
|
{
|
||||||
|
IRow row = section.row("settings.general.snapshots", "settings.general.snapshots.subtitle");
|
||||||
|
row.setSwitch(InceptumConfig.snapshots, b -> {
|
||||||
|
InceptumConfig.snapshots = b;
|
||||||
|
InceptumConfig.saveConfig();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
{
|
||||||
|
IRow row = section.row("settings.general.update-channel", "settings.general.update-channel.subtitle");
|
||||||
|
row.setDropdown(new String[] {"Stable", "CI"}, InceptumConfig.channel == UpdateChannel.CI ? 1 : 0, state -> {
|
||||||
|
InceptumConfig.channel = state == 1 ? UpdateChannel.CI : UpdateChannel.Stable;
|
||||||
|
InceptumConfig.saveConfig();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
{
|
||||||
|
IRow row = section.row("settings.general.author-name", "settings.general.author-name.subtitle");
|
||||||
|
row.setEntry(InceptumConfig.authorName, s -> {
|
||||||
|
InceptumConfig.authorName = s;
|
||||||
|
InceptumConfig.saveConfig();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
package io.gitlab.jfronny.inceptum.gtk.window.settings.launcher;
|
||||||
|
|
||||||
|
import io.gitlab.jfronny.inceptum.gtk.control.settings.SettingsWindow;
|
||||||
|
import org.gtk.gtk.Application;
|
||||||
|
|
||||||
|
public class LauncherSettingsWindow extends SettingsWindow {
|
||||||
|
public LauncherSettingsWindow(Application app) {
|
||||||
|
super(app);
|
||||||
|
addTab(new GeneralTab(this), "settings.general", "preferences-other-symbolic");
|
||||||
|
addTab(new AccountsTab(this), "settings.accounts", "system-users-symbolic");
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,6 +21,7 @@ cancel=Cancel
|
||||||
show=Show
|
show=Show
|
||||||
save=Save
|
save=Save
|
||||||
select=Select
|
select=Select
|
||||||
|
failed=Failed
|
||||||
menu.hamburger.support=Support
|
menu.hamburger.support=Support
|
||||||
menu.hamburger.preferences=Preferences
|
menu.hamburger.preferences=Preferences
|
||||||
menu.hamburger.about=About
|
menu.hamburger.about=About
|
||||||
|
@ -79,12 +80,13 @@ instance.settings.general.last-launched=Last launched: %1$s
|
||||||
instance.settings.general.game=Game
|
instance.settings.general.game=Game
|
||||||
instance.settings.general.game.version=Version
|
instance.settings.general.game.version=Version
|
||||||
instance.settings.general.game.version.subtitle=Minecraft version of this instance
|
instance.settings.general.game.version.subtitle=Minecraft version of this instance
|
||||||
settings.author-name=Author Name
|
settings.general=General
|
||||||
settings.snapshots=Snapshots
|
settings.general.author-name=Author Name
|
||||||
settings.update-channel=Update Channel
|
settings.general.snapshots=Snapshots
|
||||||
settings.snapshots.subtitle=Whether to show snapshots in the version selector for new instances
|
settings.general.update-channel=Update Channel
|
||||||
settings.update-channel.subtitle=The update channel. I personnaly recommend the CI channel as it gest the latest features and fixes more quickly, but it might be more unstable
|
settings.general.snapshots.subtitle=Whether to show snapshots in the version selector for new instances
|
||||||
settings.author-name.subtitle=The author name to add to packs where the metadata format requires specifying one
|
settings.general.update-channel.subtitle=The update channel. I personnaly recommend the CI channel as it gest the latest features and fixes more quickly, but it might be more unstable
|
||||||
|
settings.general.author-name.subtitle=The author name to add to packs where the metadata format requires specifying one
|
||||||
instance.settings.general.game.fabric.enabled=Fabric
|
instance.settings.general.game.fabric.enabled=Fabric
|
||||||
instance.settings.general.game.fabric.enabled.subtitle=Whether the Fabric Loader should be used for this instance
|
instance.settings.general.game.fabric.enabled.subtitle=Whether the Fabric Loader should be used for this instance
|
||||||
instance.settings.general.game.fabric.version=Fabric Version
|
instance.settings.general.game.fabric.version=Fabric Version
|
||||||
|
@ -94,4 +96,11 @@ instance.settings.general.game.java.subtitle=The path of the custom Java binary
|
||||||
instance.settings.general.game.memory.min=Minimum Memory
|
instance.settings.general.game.memory.min=Minimum Memory
|
||||||
instance.settings.general.game.memory.min.subtitle=The minimum amount of Memory Minecraft will allocate (in MiB)
|
instance.settings.general.game.memory.min.subtitle=The minimum amount of Memory Minecraft will allocate (in MiB)
|
||||||
instance.settings.general.game.memory.max=Maximum Memory
|
instance.settings.general.game.memory.max=Maximum Memory
|
||||||
instance.settings.general.game.memory.max.subtitle=The maximum amount of Memory Minecraft will allocate (in MiB)
|
instance.settings.general.game.memory.max.subtitle=The maximum amount of Memory Minecraft will allocate (in MiB)
|
||||||
|
settings.accounts=Accounts
|
||||||
|
instance.delete.fail=Could not delete the instance
|
||||||
|
instance.copy.fail=Could not copy instance
|
||||||
|
instance.kill.fail=Could not kill the Instance
|
||||||
|
instance.kill.prompt=Are you sure?
|
||||||
|
instance.kill.details=Killing this Instance may cause data corruption and should be avoided if possible
|
||||||
|
instance.kill=Kill
|
|
@ -20,6 +20,7 @@ cancel=Abbrechen
|
||||||
show=Anzeigen
|
show=Anzeigen
|
||||||
save=Speichern
|
save=Speichern
|
||||||
select=Auswählen
|
select=Auswählen
|
||||||
|
failed=Erfolglos
|
||||||
menu.hamburger.support=Unterstützung
|
menu.hamburger.support=Unterstützung
|
||||||
menu.hamburger.preferences=Einstellungen
|
menu.hamburger.preferences=Einstellungen
|
||||||
menu.hamburger.about=Über
|
menu.hamburger.about=Über
|
||||||
|
@ -42,7 +43,7 @@ instance.copy=Klonen
|
||||||
instance.delete=Löschen
|
instance.delete=Löschen
|
||||||
instance.delete.subtitle=Diese Instanz unwiederruflich löschen
|
instance.delete.subtitle=Diese Instanz unwiederruflich löschen
|
||||||
instance.delete.confirm=Diese Instanz wird unwiederruflich gelöscht
|
instance.delete.confirm=Diese Instanz wird unwiederruflich gelöscht
|
||||||
instance.delete.confirm.title=Bist du sicher?
|
instance.delete.confirm.title=Sind Sie sicher?
|
||||||
instance.copy.prompt=Neuer Name
|
instance.copy.prompt=Neuer Name
|
||||||
instance.copy.details=Gib den Namen für die neue Instanz ein
|
instance.copy.details=Gib den Namen für die neue Instanz ein
|
||||||
instance.settings.general=Allgemein
|
instance.settings.general=Allgemein
|
||||||
|
@ -79,12 +80,13 @@ instance.settings.general.last-launched=Zuletzt gestartet: %1$s
|
||||||
instance.settings.general.game=Game
|
instance.settings.general.game=Game
|
||||||
instance.settings.general.game.version=Version
|
instance.settings.general.game.version=Version
|
||||||
instance.settings.general.game.version.subtitle=Minecraft-Version dieser Instanz
|
instance.settings.general.game.version.subtitle=Minecraft-Version dieser Instanz
|
||||||
settings.author-name=Name des Authors
|
settings.general=Allgemein
|
||||||
settings.snapshots=Vorschauversionen
|
settings.general.author-name=Name des Authors
|
||||||
settings.update-channel=Updatekanal
|
settings.general.snapshots=Vorschauversionen
|
||||||
settings.snapshots.subtitle=Ob Vorschauversionen im Versions-Auswahlmenü gezeigt werden sollen
|
settings.general.update-channel=Updatekanal
|
||||||
settings.update-channel.subtitle=Der Update-Kanal. Ich empfehle den etwas instabileren, aber häufiger aktualisierten CI-Kanal
|
settings.general.snapshots.subtitle=Ob Vorschauversionen im Versions-Auswahlmenü gezeigt werden sollen
|
||||||
settings.author-name.subtitle=Der Name, der bei Modpack-Exporten, deren Metadaten einen Autor angeben, aufgelistet werden soll
|
settings.general.update-channel.subtitle=Der Update-Kanal. Ich empfehle den etwas instabileren, aber häufiger aktualisierten CI-Kanal
|
||||||
|
settings.general.author-name.subtitle=Der Name, der bei Modpack-Exporten, deren Metadaten einen Autor angeben, aufgelistet werden soll
|
||||||
instance.settings.general.game.fabric.enabled=Fabric
|
instance.settings.general.game.fabric.enabled=Fabric
|
||||||
instance.settings.general.game.fabric.enabled.subtitle=Ob Fabric-Loader für diese Instanz aktiviert werden soll
|
instance.settings.general.game.fabric.enabled.subtitle=Ob Fabric-Loader für diese Instanz aktiviert werden soll
|
||||||
instance.settings.general.game.fabric.version=Fabric-Version
|
instance.settings.general.game.fabric.version=Fabric-Version
|
||||||
|
@ -94,4 +96,11 @@ instance.settings.general.game.java.subtitle=Pfad der Java-Bin
|
||||||
instance.settings.general.game.memory.min=Minimale Speichernutzung
|
instance.settings.general.game.memory.min=Minimale Speichernutzung
|
||||||
instance.settings.general.game.memory.min.subtitle=Die minimale Speichernutzung dieser Instanz (in MiB)
|
instance.settings.general.game.memory.min.subtitle=Die minimale Speichernutzung dieser Instanz (in MiB)
|
||||||
instance.settings.general.game.memory.max=Maximale Speichernutzung
|
instance.settings.general.game.memory.max=Maximale Speichernutzung
|
||||||
instance.settings.general.game.memory.max.subtitle=Die maximale Speichernutzung dieser Instanz (in MiB)
|
instance.settings.general.game.memory.max.subtitle=Die maximale Speichernutzung dieser Instanz (in MiB)
|
||||||
|
settings.accounts=Konten
|
||||||
|
instance.delete.fail=Konnte die Instanz nicht löschen
|
||||||
|
instance.copy.fail=Konnte die Instanz nicht kopieren
|
||||||
|
instance.kill.fail=Ausführung konnte nicht abgebrochen werden
|
||||||
|
instance.kill.prompt=Sind Sie sicher?
|
||||||
|
instance.kill.details=Das vorzeitige Beenden von Instanzen kann zu Datenverlust führen und sollte vermieden werden
|
||||||
|
instance.kill=Beenden
|
|
@ -44,6 +44,7 @@ public class GuiUtil {
|
||||||
GuiMain.open(new ProcessStateWatcherWindow("Creating Instance", "Could not create instance", pState, cToken -> {
|
GuiMain.open(new ProcessStateWatcherWindow("Creating Instance", "Could not create instance", pState, cToken -> {
|
||||||
for (Step step : Steps.STEPS) {
|
for (Step step : Steps.STEPS) {
|
||||||
if (cToken.get()) return;
|
if (cToken.get()) return;
|
||||||
|
pState.incrementStep(step.name);
|
||||||
step.execute(state, cToken);
|
step.execute(state, cToken);
|
||||||
}
|
}
|
||||||
LauncherEnv.showInfo("The instance was successfully created. You can now launch it using the main menu", "Successfully installed");
|
LauncherEnv.showInfo("The instance was successfully created. You can now launch it using the main menu", "Successfully installed");
|
||||||
|
|
|
@ -123,6 +123,27 @@ public record Instance(String id, Path path, InstanceMeta meta, ModsDirScanner m
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean kill() {
|
||||||
|
if (!isRunningLocked()) {
|
||||||
|
Utils.LOGGER.info("Already killed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (!ProcessUtils.kill(Files.readString(path.resolve(LOCK_NAME)))) {
|
||||||
|
Utils.LOGGER.error("Could not kill instance");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (isRunningLocked()) {
|
||||||
|
Utils.LOGGER.error("Still running after kill");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} catch (IOException e) {
|
||||||
|
Utils.LOGGER.error("Could not read running lock of " + name, e);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public void setRunningLock(long pid) throws IOException {
|
public void setRunningLock(long pid) throws IOException {
|
||||||
Files.writeString(path.resolve(LOCK_NAME), Long.toString(pid));
|
Files.writeString(path.resolve(LOCK_NAME), Long.toString(pid));
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package io.gitlab.jfronny.inceptum.launcher.system.instance;
|
||||||
import gsoncompile.extensions.io.gitlab.jfronny.inceptum.launcher.model.inceptum.InstanceMeta.GC_InstanceMeta;
|
import gsoncompile.extensions.io.gitlab.jfronny.inceptum.launcher.model.inceptum.InstanceMeta.GC_InstanceMeta;
|
||||||
import io.gitlab.jfronny.commons.io.JFiles;
|
import io.gitlab.jfronny.commons.io.JFiles;
|
||||||
import io.gitlab.jfronny.commons.throwable.ThrowingConsumer;
|
import io.gitlab.jfronny.commons.throwable.ThrowingConsumer;
|
||||||
|
import io.gitlab.jfronny.commons.throwable.ThrowingRunnable;
|
||||||
import io.gitlab.jfronny.inceptum.common.MetaHolder;
|
import io.gitlab.jfronny.inceptum.common.MetaHolder;
|
||||||
import io.gitlab.jfronny.inceptum.common.Utils;
|
import io.gitlab.jfronny.inceptum.common.Utils;
|
||||||
import io.gitlab.jfronny.inceptum.launcher.model.inceptum.InstanceMeta;
|
import io.gitlab.jfronny.inceptum.launcher.model.inceptum.InstanceMeta;
|
||||||
|
@ -13,10 +14,17 @@ import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
public class InstanceList {
|
public class InstanceList {
|
||||||
private static final Map<Path, IEntry> metas = new LinkedHashMap<>();
|
private static final Map<Path, IEntry> metas = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
public static <TEx extends Throwable> void lock(ThrowingRunnable<TEx> task) throws TEx {
|
||||||
|
synchronized (metas) {
|
||||||
|
task.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void reset() {
|
public static void reset() {
|
||||||
synchronized (metas) {
|
synchronized (metas) {
|
||||||
for (var entry : metas.entrySet()) {
|
for (var entry : metas.entrySet()) {
|
||||||
|
@ -55,6 +63,13 @@ public class InstanceList {
|
||||||
return JFiles.list(MetaHolder.INSTANCE_DIR, InstanceList::isInstance).isEmpty;
|
return JFiles.list(MetaHolder.INSTANCE_DIR, InstanceList::isInstance).isEmpty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int size() throws IOException {
|
||||||
|
if (!Files.exists(MetaHolder.INSTANCE_DIR)) return 0;
|
||||||
|
try (Stream<Path> list = Files.list(MetaHolder.INSTANCE_DIR)) {
|
||||||
|
return (int) list.filter(InstanceList::isInstance).count();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static Instance read(Path instancePath) throws IOException {
|
public static Instance read(Path instancePath) throws IOException {
|
||||||
Objects.requireNonNull(instancePath);
|
Objects.requireNonNull(instancePath);
|
||||||
synchronized (metas) {
|
synchronized (metas) {
|
||||||
|
|
|
@ -149,28 +149,41 @@ public class InstanceLauncher {
|
||||||
Runnable starterRunner = () -> {
|
Runnable starterRunner = () -> {
|
||||||
try {
|
try {
|
||||||
proc.set(pb.start());
|
proc.set(pb.start());
|
||||||
instance.setRunningLock(proc.get().pid());
|
instance.runningLock = proc.get().pid();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Utils.LOGGER.error("Could not start " + launchType.name, e);
|
Utils.LOGGER.error("Could not start " + launchType.name, e);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
starterRunner.run();
|
|
||||||
if (restart) {
|
if (restart) {
|
||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
while (true) {
|
while (true) {
|
||||||
|
starterRunner.run();
|
||||||
|
if (!proc.get().isAlive) {
|
||||||
|
Utils.LOGGER.error("Could not create server process");
|
||||||
|
instance.isRunningLocked();
|
||||||
|
return;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
proc.get().waitFor();
|
proc.get().waitFor();
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
Utils.LOGGER.error("Could not wait for server to finish", e);
|
Utils.LOGGER.error("Could not wait for server to finish", e);
|
||||||
}
|
}
|
||||||
Utils.LOGGER.info("Restarting server");
|
Utils.LOGGER.info("Restarting server");
|
||||||
starterRunner.run();
|
|
||||||
if (!proc.get().isAlive) {
|
|
||||||
Utils.LOGGER.error("Could not restart server");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}).start();
|
}).start();
|
||||||
|
} else {
|
||||||
|
var th = new Thread(() -> {
|
||||||
|
starterRunner.run();
|
||||||
|
try {
|
||||||
|
proc.get().waitFor();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
Utils.LOGGER.error("Could not wait for thread", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
instance.isRunningLocked();
|
||||||
|
});
|
||||||
|
th.isDaemon = true;
|
||||||
|
th.start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,4 +5,5 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
public interface Step {
|
public interface Step {
|
||||||
void execute(SetupStepInfo info, AtomicBoolean stopThread) throws IOException;
|
void execute(SetupStepInfo info, AtomicBoolean stopThread) throws IOException;
|
||||||
|
String getName();
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ public class Steps {
|
||||||
: LoaderInfo.NONE;
|
: LoaderInfo.NONE;
|
||||||
SetupStepInfo info = new SetupStepInfo(vi, li, instance.name, state);
|
SetupStepInfo info = new SetupStepInfo(vi, li, instance.name, state);
|
||||||
for (Step step : Steps.STEPS) {
|
for (Step step : Steps.STEPS) {
|
||||||
state.incrementStep("Starting " + step.getClass().getSimpleName());
|
state.incrementStep(step.name);
|
||||||
step.execute(info, cancel);
|
step.execute(info, cancel);
|
||||||
if (cancel.get()) return;
|
if (cancel.get()) return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,4 +31,9 @@ public class DownloadAssetsStep implements Step {
|
||||||
throw new IOException("Could not download assets", e);
|
throw new IOException("Could not download assets", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "Downloading Assets";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,4 +52,9 @@ public class DownloadClientStep implements Step {
|
||||||
throw new IOException("Could not download client", e);
|
throw new IOException("Could not download client", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "Downloading Game";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,4 +41,9 @@ public class DownloadJavaStep implements Step {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "Downloading Java";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,11 @@ public class DownloadLibrariesStep implements Step {
|
||||||
execute(info.version, stopThread, info.currentState);
|
execute(info.version, stopThread, info.currentState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "Downloading Libraries";
|
||||||
|
}
|
||||||
|
|
||||||
public static void execute(VersionInfo version, AtomicBoolean stopThread, ProcessState currentState) throws IOException {
|
public static void execute(VersionInfo version, AtomicBoolean stopThread, ProcessState currentState) throws IOException {
|
||||||
for (ArtifactInfo artifact : VersionInfoLibraryResolver.getRelevant(version)) {
|
for (ArtifactInfo artifact : VersionInfoLibraryResolver.getRelevant(version)) {
|
||||||
if (stopThread.get()) return;
|
if (stopThread.get()) return;
|
||||||
|
|
|
@ -19,4 +19,9 @@ public class RunMdsStep implements Step {
|
||||||
ModsDirScanner.get(instance.resolve("mods"), GC_InstanceMeta.read(instance.resolve(Instance.CONFIG_NAME)))
|
ModsDirScanner.get(instance.resolve("mods"), GC_InstanceMeta.read(instance.resolve(Instance.CONFIG_NAME)))
|
||||||
.runOnce((path, iwModDescription) -> info.setState("Scanned " + path));
|
.runOnce((path, iwModDescription) -> info.setState("Scanned " + path));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "Running mod discovery system";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,4 +35,9 @@ public class SetupDirsStep implements Step {
|
||||||
}
|
}
|
||||||
Files.createDirectories(MetaHolder.NATIVES_DIR.resolve(GameVersionParser.getGameVersion(info.version.id)));
|
Files.createDirectories(MetaHolder.NATIVES_DIR.resolve(GameVersionParser.getGameVersion(info.version.id)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "Setting up directories";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,4 +43,9 @@ public class WriteMetadataStep implements Step {
|
||||||
Files.writeString(instance.resolve(".iceignore"), Instance.CONFIG_NAME);
|
Files.writeString(instance.resolve(".iceignore"), Instance.CONFIG_NAME);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "Writing Metadata";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,13 @@ public class ProcessUtils {
|
||||||
return isProcessIdRunning(pid, "ps", "-p", pid);
|
return isProcessIdRunning(pid, "ps", "-p", pid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean kill(String pid) {
|
||||||
|
//TODO test on windows
|
||||||
|
if (OSUtils.TYPE == OSUtils.Type.WINDOWS)
|
||||||
|
return kill("taskkill", "/f", "/pid", pid);
|
||||||
|
return kill("kill", "--timeout", "500", "KILL", pid);
|
||||||
|
}
|
||||||
|
|
||||||
private static boolean isProcessIdRunning(String pid, String... command) {
|
private static boolean isProcessIdRunning(String pid, String... command) {
|
||||||
try {
|
try {
|
||||||
Runtime rt = Runtime.getRuntime();
|
Runtime rt = Runtime.getRuntime();
|
||||||
|
@ -33,4 +40,17 @@ public class ProcessUtils {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean kill(String... command) {
|
||||||
|
try {
|
||||||
|
Runtime rt = Runtime.getRuntime();
|
||||||
|
Process pr = rt.exec(command);
|
||||||
|
pr.waitFor();
|
||||||
|
Thread.sleep(100); // Ensure the signal is processed by waiting this randomly picked amount of time
|
||||||
|
return pr.exitValue() == 0;
|
||||||
|
} catch (Exception e) {
|
||||||
|
Utils.LOGGER.error("Could not kill process", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue