Revert "[Architecture] Kotlin VanillaPacksTab (#717)"
This reverts commit 591ec36136
.
This commit is contained in:
parent
f3a7d575e6
commit
2914ac1383
8 changed files with 941 additions and 1683 deletions
|
@ -1,6 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="KotlinJpsPluginSettings">
|
||||
<option name="version" value="1.8.0" />
|
||||
</component>
|
||||
</project>
|
|
@ -20,6 +20,3 @@ This changelog only contains the changes that are unreleased. For changes for in
|
|||
- Issue with mod images not being scaled smoothly [#731]
|
||||
|
||||
### Misc
|
||||
- Add `xrandr` as a dependency for RPM [#691]
|
||||
- Update packaging scripts
|
||||
- Implement view model for VanillaPacksTab [#717]
|
||||
|
|
|
@ -27,7 +27,6 @@ plugins {
|
|||
id 'de.undercouch.download' version '5.1.0'
|
||||
id 'com.github.johnrengelman.shadow' version '7.1.2'
|
||||
id 'com.github.ben-manes.versions' version '0.42.0'
|
||||
id "org.jetbrains.kotlin.jvm" version "1.8.0"
|
||||
id 'com.apollographql.apollo' version '2.5.14'
|
||||
}
|
||||
|
||||
|
@ -85,11 +84,6 @@ dependencies {
|
|||
implementation 'com.github.hypfvieh:dbus-java:3.3.1'
|
||||
implementation 'com.apollographql.apollo:apollo-runtime:2.5.14'
|
||||
implementation 'com.apollographql.apollo:apollo-http-cache:2.5.14'
|
||||
implementation 'com.apollographql.apollo:apollo-coroutines-support:2.5.14'
|
||||
|
||||
// Kotlin
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-swing:1.6.4")
|
||||
|
||||
testImplementation 'junit:junit:4.13.2'
|
||||
testImplementation 'org.mockito:mockito-core:4.6.1'
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
/*
|
||||
* ATLauncher - https://github.com/ATLauncher/ATLauncher
|
||||
* Copyright (C) 2013-2022 ATLauncher
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.atlauncher.data
|
||||
|
||||
/**
|
||||
* Specifies a row to display in the VanillaPacksTab
|
||||
*
|
||||
* @see [com.atlauncher.gui.tabs.VanillaPacksTab]
|
||||
*/
|
||||
class MCVersionRow(val id: String, val date: String, val type: String)
|
941
src/main/java/com/atlauncher/gui/tabs/VanillaPacksTab.java
Normal file
941
src/main/java/com/atlauncher/gui/tabs/VanillaPacksTab.java
Normal file
|
@ -0,0 +1,941 @@
|
|||
/*
|
||||
* ATLauncher - https://github.com/ATLauncher/ATLauncher
|
||||
* Copyright (C) 2013-2022 ATLauncher
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.atlauncher.gui.tabs;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.FlowLayout;
|
||||
import java.awt.GridBagConstraints;
|
||||
import java.awt.GridBagLayout;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.swing.Box;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.ButtonGroup;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JRadioButton;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTable;
|
||||
import javax.swing.JTextArea;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.ListSelectionModel;
|
||||
import javax.swing.event.DocumentEvent;
|
||||
import javax.swing.event.DocumentListener;
|
||||
import javax.swing.event.ListSelectionEvent;
|
||||
import javax.swing.event.ListSelectionListener;
|
||||
import javax.swing.table.DefaultTableModel;
|
||||
import javax.swing.table.TableColumnModel;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.joda.time.format.DateTimeFormat;
|
||||
import org.joda.time.format.DateTimeFormatter;
|
||||
import org.joda.time.format.ISODateTimeFormat;
|
||||
import org.mini2Dx.gettext.GetText;
|
||||
|
||||
import com.apollographql.apollo.ApolloCall;
|
||||
import com.apollographql.apollo.api.Response;
|
||||
import com.apollographql.apollo.api.cache.http.HttpCachePolicy;
|
||||
import com.apollographql.apollo.api.cache.http.HttpCachePolicy.FetchStrategy;
|
||||
import com.apollographql.apollo.exception.ApolloException;
|
||||
import com.atlauncher.App;
|
||||
import com.atlauncher.builders.HTMLBuilder;
|
||||
import com.atlauncher.constants.UIConstants;
|
||||
import com.atlauncher.data.installables.Installable;
|
||||
import com.atlauncher.data.installables.VanillaInstallable;
|
||||
import com.atlauncher.data.minecraft.VersionManifestVersion;
|
||||
import com.atlauncher.data.minecraft.VersionManifestVersionType;
|
||||
import com.atlauncher.data.minecraft.loaders.LoaderType;
|
||||
import com.atlauncher.data.minecraft.loaders.LoaderVersion;
|
||||
import com.atlauncher.data.minecraft.loaders.fabric.FabricLoader;
|
||||
import com.atlauncher.data.minecraft.loaders.forge.ForgeLoader;
|
||||
import com.atlauncher.data.minecraft.loaders.legacyfabric.LegacyFabricLoader;
|
||||
import com.atlauncher.data.minecraft.loaders.quilt.QuiltLoader;
|
||||
import com.atlauncher.exceptions.InvalidMinecraftVersion;
|
||||
import com.atlauncher.graphql.GetLoaderVersionsForMinecraftVersionQuery;
|
||||
import com.atlauncher.managers.ConfigManager;
|
||||
import com.atlauncher.managers.DialogManager;
|
||||
import com.atlauncher.managers.InstanceManager;
|
||||
import com.atlauncher.managers.LogManager;
|
||||
import com.atlauncher.managers.MinecraftManager;
|
||||
import com.atlauncher.network.GraphqlClient;
|
||||
import com.atlauncher.utils.ComboItem;
|
||||
import com.atlauncher.utils.Pair;
|
||||
import com.atlauncher.utils.Utils;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public final class VanillaPacksTab extends JPanel implements Tab {
|
||||
private final List<VersionManifestVersionType> minecraftVersionTypeFilters = new ArrayList<>(
|
||||
Arrays.asList(VersionManifestVersionType.RELEASE));
|
||||
private String selectedMinecraftVersion = null;
|
||||
|
||||
private final JTextField nameField = new JTextField(32);
|
||||
private boolean nameFieldDirty = false;
|
||||
|
||||
private final JTextArea descriptionField = new JTextArea(2, 40);
|
||||
private boolean descriptionFieldDirty = false;
|
||||
|
||||
private final JCheckBox minecraftVersionReleasesFilterCheckbox = new JCheckBox(GetText.tr("Releases"));
|
||||
private final JCheckBox minecraftVersionExperimentsFilterCheckbox = new JCheckBox(GetText.tr("Experiments"));
|
||||
private final JCheckBox minecraftVersionSnapshotsFilterCheckbox = new JCheckBox(GetText.tr("Snapshots"));
|
||||
private final JCheckBox minecraftVersionBetasFilterCheckbox = new JCheckBox(GetText.tr("Betas"));
|
||||
private final JCheckBox minecraftVersionAlphasFilterCheckbox = new JCheckBox(GetText.tr("Alphas"));
|
||||
|
||||
private JTable minecraftVersionTable;
|
||||
private DefaultTableModel minecraftVersionTableModel;
|
||||
|
||||
private final ButtonGroup loaderTypeButtonGroup = new ButtonGroup();
|
||||
private final JRadioButton loaderTypeNoneRadioButton = new JRadioButton(GetText.tr("None"));
|
||||
private final JRadioButton loaderTypeFabricRadioButton = new JRadioButton("Fabric");
|
||||
private final JRadioButton loaderTypeForgeRadioButton = new JRadioButton("Forge");
|
||||
private final JRadioButton loaderTypeLegacyFabricRadioButton = new JRadioButton("Legacy Fabric");
|
||||
private final JRadioButton loaderTypeQuiltRadioButton = new JRadioButton("Quilt");
|
||||
|
||||
private final JComboBox<ComboItem<LoaderVersion>> loaderVersionsDropDown = new JComboBox<>();
|
||||
|
||||
private final JButton createServerButton = new JButton(GetText.tr("Create Server"));
|
||||
private final JButton createInstanceButton = new JButton(GetText.tr("Create Instance"));
|
||||
|
||||
public VanillaPacksTab() {
|
||||
super(new BorderLayout());
|
||||
setName("vanillaPacksPanel");
|
||||
|
||||
setupMainPanel();
|
||||
setupBottomPanel();
|
||||
}
|
||||
|
||||
private void setupMainPanel() {
|
||||
JPanel mainPanel = new JPanel(new GridBagLayout());
|
||||
GridBagConstraints gbc = new GridBagConstraints();
|
||||
|
||||
// Name
|
||||
gbc.gridx = 0;
|
||||
gbc.gridy = 0;
|
||||
gbc.insets = UIConstants.LABEL_INSETS;
|
||||
gbc.anchor = GridBagConstraints.EAST;
|
||||
|
||||
JLabel nameLabel = new JLabel(GetText.tr("Instance Name") + ":");
|
||||
mainPanel.add(nameLabel, gbc);
|
||||
|
||||
gbc.gridx++;
|
||||
gbc.insets = UIConstants.FIELD_INSETS;
|
||||
gbc.anchor = GridBagConstraints.BASELINE_LEADING;
|
||||
|
||||
nameField.getDocument().addDocumentListener(new DocumentListener() {
|
||||
@Override
|
||||
public void changedUpdate(DocumentEvent e) {
|
||||
checkDirty(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insertUpdate(DocumentEvent e) {
|
||||
checkDirty(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeUpdate(DocumentEvent e) {
|
||||
checkDirty(e);
|
||||
}
|
||||
|
||||
private void checkDirty(DocumentEvent e) {
|
||||
if (selectedMinecraftVersion == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String currentValue = nameField.getText();
|
||||
LoaderType selectedLoader = getSelectedLoader();
|
||||
|
||||
// if the name is the same as the default is, then we're not dirty
|
||||
nameFieldDirty = !(currentValue.equals(String.format("Minecraft %s", selectedMinecraftVersion))
|
||||
|| (selectedLoader != null && currentValue.equals(
|
||||
String.format("Minecraft %s with %s", selectedMinecraftVersion, selectedLoader))));
|
||||
}
|
||||
});
|
||||
mainPanel.add(nameField, gbc);
|
||||
|
||||
// Description
|
||||
gbc.gridx = 0;
|
||||
gbc.gridy++;
|
||||
gbc.insets = UIConstants.LABEL_INSETS;
|
||||
gbc.anchor = GridBagConstraints.BASELINE_TRAILING;
|
||||
|
||||
JLabel descriptionLabel = new JLabel(GetText.tr("Description") + ":");
|
||||
mainPanel.add(descriptionLabel, gbc);
|
||||
|
||||
gbc.gridx++;
|
||||
gbc.insets = UIConstants.FIELD_INSETS;
|
||||
gbc.anchor = GridBagConstraints.BASELINE_LEADING;
|
||||
|
||||
JScrollPane descriptionScrollPane = new JScrollPane(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
|
||||
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
|
||||
descriptionScrollPane.setPreferredSize(new Dimension(450, 80));
|
||||
descriptionScrollPane.setViewportView(descriptionField);
|
||||
|
||||
descriptionField.getDocument().addDocumentListener(new DocumentListener() {
|
||||
@Override
|
||||
public void changedUpdate(DocumentEvent e) {
|
||||
checkDirty(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insertUpdate(DocumentEvent e) {
|
||||
checkDirty(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeUpdate(DocumentEvent e) {
|
||||
checkDirty(e);
|
||||
}
|
||||
|
||||
private void checkDirty(DocumentEvent e) {
|
||||
if (selectedMinecraftVersion == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String currentValue = descriptionField.getText();
|
||||
LoaderType selectedLoader = getSelectedLoader();
|
||||
|
||||
// if the description is the same as the default is, then we're not dirty
|
||||
descriptionFieldDirty = !(currentValue.equals(String.format("Minecraft %s", selectedMinecraftVersion))
|
||||
|| (selectedLoader != null && currentValue.equals(
|
||||
String.format("Minecraft %s with %s", selectedMinecraftVersion, selectedLoader))));
|
||||
}
|
||||
});
|
||||
mainPanel.add(descriptionScrollPane, gbc);
|
||||
|
||||
// Minecraft Version
|
||||
gbc.gridx = 0;
|
||||
gbc.gridy += 2;
|
||||
gbc.insets = UIConstants.LABEL_INSETS;
|
||||
gbc.anchor = GridBagConstraints.NORTHEAST;
|
||||
|
||||
JPanel minecraftVersionPanel = new JPanel();
|
||||
minecraftVersionPanel.setLayout(new BoxLayout(minecraftVersionPanel, BoxLayout.Y_AXIS));
|
||||
|
||||
JLabel minecraftVersionLabel = new JLabel(GetText.tr("Minecraft Version") + ":");
|
||||
minecraftVersionPanel.add(minecraftVersionLabel);
|
||||
|
||||
minecraftVersionPanel.add(Box.createVerticalStrut(20));
|
||||
|
||||
JPanel minecraftVersionFilterPanel = new JPanel();
|
||||
minecraftVersionFilterPanel.setLayout(new BoxLayout(minecraftVersionFilterPanel, BoxLayout.Y_AXIS));
|
||||
|
||||
JLabel minecraftVersionFilterLabel = new JLabel(GetText.tr("Filter"));
|
||||
minecraftVersionFilterLabel.setFont(App.THEME.getBoldFont());
|
||||
minecraftVersionFilterPanel.add(minecraftVersionFilterLabel);
|
||||
|
||||
minecraftVersionReleasesFilterCheckbox.setSelected(true);
|
||||
minecraftVersionReleasesFilterCheckbox.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
if (minecraftVersionReleasesFilterCheckbox.isSelected()) {
|
||||
minecraftVersionTypeFilters.add(VersionManifestVersionType.RELEASE);
|
||||
} else {
|
||||
minecraftVersionTypeFilters.remove(VersionManifestVersionType.RELEASE);
|
||||
}
|
||||
|
||||
reloadMinecraftVersionsTable();
|
||||
}
|
||||
});
|
||||
if (ConfigManager.getConfigItem("minecraft.release.enabled", true) == true) {
|
||||
minecraftVersionFilterPanel.add(minecraftVersionReleasesFilterCheckbox);
|
||||
}
|
||||
|
||||
minecraftVersionExperimentsFilterCheckbox.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
if (minecraftVersionExperimentsFilterCheckbox.isSelected()) {
|
||||
minecraftVersionTypeFilters.add(VersionManifestVersionType.EXPERIMENT);
|
||||
} else {
|
||||
minecraftVersionTypeFilters.remove(VersionManifestVersionType.EXPERIMENT);
|
||||
}
|
||||
|
||||
reloadMinecraftVersionsTable();
|
||||
}
|
||||
});
|
||||
if (ConfigManager.getConfigItem("minecraft.experiment.enabled", true) == true) {
|
||||
minecraftVersionFilterPanel.add(minecraftVersionExperimentsFilterCheckbox);
|
||||
}
|
||||
|
||||
minecraftVersionSnapshotsFilterCheckbox.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
if (minecraftVersionSnapshotsFilterCheckbox.isSelected()) {
|
||||
minecraftVersionTypeFilters.add(VersionManifestVersionType.SNAPSHOT);
|
||||
} else {
|
||||
minecraftVersionTypeFilters.remove(VersionManifestVersionType.SNAPSHOT);
|
||||
}
|
||||
|
||||
reloadMinecraftVersionsTable();
|
||||
}
|
||||
});
|
||||
if (ConfigManager.getConfigItem("minecraft.snapshot.enabled", true) == true) {
|
||||
minecraftVersionFilterPanel.add(minecraftVersionSnapshotsFilterCheckbox);
|
||||
}
|
||||
|
||||
minecraftVersionBetasFilterCheckbox.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
if (minecraftVersionBetasFilterCheckbox.isSelected()) {
|
||||
minecraftVersionTypeFilters.add(VersionManifestVersionType.OLD_BETA);
|
||||
} else {
|
||||
minecraftVersionTypeFilters.remove(VersionManifestVersionType.OLD_BETA);
|
||||
}
|
||||
|
||||
reloadMinecraftVersionsTable();
|
||||
}
|
||||
});
|
||||
if (ConfigManager.getConfigItem("minecraft.old_alpha.enabled", true) == true) {
|
||||
minecraftVersionFilterPanel.add(minecraftVersionBetasFilterCheckbox);
|
||||
}
|
||||
|
||||
minecraftVersionAlphasFilterCheckbox.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
if (minecraftVersionAlphasFilterCheckbox.isSelected()) {
|
||||
minecraftVersionTypeFilters.add(VersionManifestVersionType.OLD_ALPHA);
|
||||
} else {
|
||||
minecraftVersionTypeFilters.remove(VersionManifestVersionType.OLD_ALPHA);
|
||||
}
|
||||
|
||||
reloadMinecraftVersionsTable();
|
||||
}
|
||||
});
|
||||
if (ConfigManager.getConfigItem("minecraft.old_beta.enabled", true) == true) {
|
||||
minecraftVersionFilterPanel.add(minecraftVersionAlphasFilterCheckbox);
|
||||
}
|
||||
|
||||
minecraftVersionPanel.add(minecraftVersionFilterPanel);
|
||||
|
||||
mainPanel.add(minecraftVersionPanel, gbc);
|
||||
|
||||
gbc.gridx++;
|
||||
gbc.insets = UIConstants.FIELD_INSETS;
|
||||
gbc.anchor = GridBagConstraints.BASELINE_LEADING;
|
||||
|
||||
JScrollPane minecraftVersionScrollPane = new JScrollPane(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
|
||||
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
|
||||
|
||||
minecraftVersionScrollPane.setPreferredSize(new Dimension(450, 300));
|
||||
|
||||
setupMinecraftVersionsTable();
|
||||
reloadMinecraftVersionsTable();
|
||||
minecraftVersionScrollPane.setViewportView(minecraftVersionTable);
|
||||
|
||||
mainPanel.add(minecraftVersionScrollPane, gbc);
|
||||
|
||||
// Loader Type
|
||||
gbc.gridx = 0;
|
||||
gbc.gridy++;
|
||||
gbc.insets = UIConstants.LABEL_INSETS;
|
||||
gbc.anchor = GridBagConstraints.EAST;
|
||||
|
||||
JLabel loaderTypeLabel = new JLabel(GetText.tr("Loader") + "?");
|
||||
mainPanel.add(loaderTypeLabel, gbc);
|
||||
|
||||
gbc.gridx++;
|
||||
gbc.insets = UIConstants.FIELD_INSETS;
|
||||
gbc.anchor = GridBagConstraints.BASELINE_LEADING;
|
||||
|
||||
loaderTypeButtonGroup.add(loaderTypeNoneRadioButton);
|
||||
loaderTypeButtonGroup.add(loaderTypeFabricRadioButton);
|
||||
loaderTypeButtonGroup.add(loaderTypeForgeRadioButton);
|
||||
loaderTypeButtonGroup.add(loaderTypeLegacyFabricRadioButton);
|
||||
loaderTypeButtonGroup.add(loaderTypeQuiltRadioButton);
|
||||
|
||||
JPanel loaderTypePanel = new JPanel(new FlowLayout());
|
||||
loaderTypePanel.add(loaderTypeNoneRadioButton);
|
||||
|
||||
if (ConfigManager.getConfigItem("loaders.fabric.enabled", true) == true) {
|
||||
loaderTypePanel.add(loaderTypeFabricRadioButton);
|
||||
}
|
||||
|
||||
if (ConfigManager.getConfigItem("loaders.forge.enabled", true) == true) {
|
||||
loaderTypePanel.add(loaderTypeForgeRadioButton);
|
||||
}
|
||||
|
||||
if (ConfigManager.getConfigItem("loaders.legacyfabric.enabled", true) == true) {
|
||||
loaderTypePanel.add(loaderTypeLegacyFabricRadioButton);
|
||||
}
|
||||
|
||||
if (ConfigManager.getConfigItem("loaders.quilt.enabled", false) == true) {
|
||||
loaderTypePanel.add(loaderTypeQuiltRadioButton);
|
||||
}
|
||||
|
||||
loaderTypeNoneRadioButton.addActionListener(e -> {
|
||||
selectedLoaderTypeChanged(null);
|
||||
});
|
||||
loaderTypeFabricRadioButton.addActionListener(e -> {
|
||||
selectedLoaderTypeChanged(LoaderType.FABRIC);
|
||||
});
|
||||
loaderTypeForgeRadioButton.addActionListener(e -> {
|
||||
selectedLoaderTypeChanged(LoaderType.FORGE);
|
||||
});
|
||||
loaderTypeLegacyFabricRadioButton.addActionListener(e -> {
|
||||
selectedLoaderTypeChanged(LoaderType.LEGACY_FABRIC);
|
||||
});
|
||||
loaderTypeQuiltRadioButton.addActionListener(e -> {
|
||||
selectedLoaderTypeChanged(LoaderType.QUILT);
|
||||
});
|
||||
|
||||
loaderTypeNoneRadioButton.setSelected(true);
|
||||
|
||||
mainPanel.add(loaderTypePanel, gbc);
|
||||
|
||||
// Loader Version
|
||||
gbc.gridx = 0;
|
||||
gbc.gridy++;
|
||||
gbc.insets = UIConstants.LABEL_INSETS;
|
||||
gbc.anchor = GridBagConstraints.BASELINE_TRAILING;
|
||||
|
||||
JLabel loaderVersionLabel = new JLabel(GetText.tr("Loader Version") + ":");
|
||||
mainPanel.add(loaderVersionLabel, gbc);
|
||||
|
||||
gbc.gridx++;
|
||||
gbc.insets = UIConstants.FIELD_INSETS;
|
||||
gbc.anchor = GridBagConstraints.BASELINE_LEADING;
|
||||
|
||||
loaderVersionsDropDown.setEnabled(false);
|
||||
loaderVersionsDropDown.addItem(new ComboItem<LoaderVersion>(null, GetText.tr("Select Loader First")));
|
||||
mainPanel.add(loaderVersionsDropDown, gbc);
|
||||
|
||||
add(mainPanel, BorderLayout.CENTER);
|
||||
}
|
||||
|
||||
private void setupMinecraftVersionsTable() {
|
||||
minecraftVersionTableModel = new DefaultTableModel(new String[][] {},
|
||||
new String[] { GetText.tr("Version"), GetText.tr("Released"), GetText.tr("Type") }) {
|
||||
|
||||
@Override
|
||||
public boolean isCellEditable(int rowIndex, int columnIndex) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
minecraftVersionTable = new JTable(minecraftVersionTableModel);
|
||||
minecraftVersionTable.getTableHeader().setReorderingAllowed(false);
|
||||
|
||||
ListSelectionModel sm = minecraftVersionTable.getSelectionModel();
|
||||
sm.addListSelectionListener(new ListSelectionListener() {
|
||||
@Override
|
||||
public void valueChanged(ListSelectionEvent e) {
|
||||
if (e.getValueIsAdjusting()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ListSelectionModel lsm = (ListSelectionModel) e.getSource();
|
||||
|
||||
int minIndex = lsm.getMinSelectionIndex();
|
||||
int maxIndex = lsm.getMaxSelectionIndex();
|
||||
for (int i = minIndex; i <= maxIndex; i++) {
|
||||
if (lsm.isSelectedIndex(i)) {
|
||||
selectedMinecraftVersionChanged((String) minecraftVersionTableModel.getValueAt(i, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
TableColumnModel cm = minecraftVersionTable.getColumnModel();
|
||||
cm.getColumn(0).setResizable(false);
|
||||
|
||||
cm.getColumn(1).setResizable(false);
|
||||
cm.getColumn(1).setMaxWidth(200);
|
||||
|
||||
cm.getColumn(2).setResizable(false);
|
||||
cm.getColumn(2).setMaxWidth(200);
|
||||
|
||||
minecraftVersionTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||
minecraftVersionTable.setShowVerticalLines(false);
|
||||
}
|
||||
|
||||
private void selectedMinecraftVersionChanged(String newSelectedMinecraftVersion) {
|
||||
if (selectedMinecraftVersion != newSelectedMinecraftVersion) {
|
||||
selectedMinecraftVersion = newSelectedMinecraftVersion;
|
||||
String defaultValue = String.format("Minecraft %s", newSelectedMinecraftVersion);
|
||||
|
||||
try {
|
||||
VersionManifestVersion version = MinecraftManager.getMinecraftVersion(newSelectedMinecraftVersion);
|
||||
createServerButton.setVisible(version.hasServer());
|
||||
} catch (InvalidMinecraftVersion ignored) {
|
||||
createServerButton.setVisible(false);
|
||||
}
|
||||
|
||||
if (!nameFieldDirty) {
|
||||
nameField.setText(defaultValue);
|
||||
}
|
||||
|
||||
if (!descriptionFieldDirty) {
|
||||
descriptionField.setText(defaultValue);
|
||||
}
|
||||
|
||||
loaderTypeFabricRadioButton.setVisible(
|
||||
!ConfigManager.getConfigItem("loaders.fabric.disabledMinecraftVersions", new ArrayList<String>())
|
||||
.contains(newSelectedMinecraftVersion));
|
||||
loaderTypeForgeRadioButton.setVisible(
|
||||
!ConfigManager.getConfigItem("loaders.forge.disabledMinecraftVersions", new ArrayList<String>())
|
||||
.contains(newSelectedMinecraftVersion));
|
||||
loaderTypeLegacyFabricRadioButton.setVisible(
|
||||
!ConfigManager
|
||||
.getConfigItem("loaders.legacyfabric.disabledMinecraftVersions", new ArrayList<String>())
|
||||
.contains(newSelectedMinecraftVersion));
|
||||
loaderTypeQuiltRadioButton.setVisible(
|
||||
!ConfigManager.getConfigItem("loaders.quilt.disabledMinecraftVersions", new ArrayList<String>())
|
||||
.contains(newSelectedMinecraftVersion));
|
||||
|
||||
// refresh the loader versions if we have one selected
|
||||
LoaderType selectedLoaderType = getSelectedLoader();
|
||||
if (selectedLoaderType != null) {
|
||||
selectedLoaderTypeChanged(selectedLoaderType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private LoaderType getSelectedLoader() {
|
||||
if (loaderTypeFabricRadioButton.isSelected()) {
|
||||
return LoaderType.FABRIC;
|
||||
}
|
||||
|
||||
if (loaderTypeForgeRadioButton.isSelected()) {
|
||||
return LoaderType.FORGE;
|
||||
}
|
||||
|
||||
if (loaderTypeLegacyFabricRadioButton.isSelected()) {
|
||||
return LoaderType.LEGACY_FABRIC;
|
||||
}
|
||||
|
||||
if (loaderTypeQuiltRadioButton.isSelected()) {
|
||||
return LoaderType.QUILT;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void reloadMinecraftVersionsTable() {
|
||||
// remove all rows
|
||||
int rowCount = minecraftVersionTableModel.getRowCount();
|
||||
if (rowCount > 0) {
|
||||
for (int i = rowCount - 1; i >= 0; i--) {
|
||||
minecraftVersionTableModel.removeRow(i);
|
||||
}
|
||||
}
|
||||
|
||||
List<VersionManifestVersion> minecraftVersions = MinecraftManager
|
||||
.getFilteredMinecraftVersions(minecraftVersionTypeFilters);
|
||||
|
||||
DateTimeFormatter fmt = DateTimeFormat.forPattern(App.settings.dateFormat);
|
||||
minecraftVersions.stream().forEach(mv -> {
|
||||
minecraftVersionTableModel.addRow(new String[] { mv.id,
|
||||
fmt.print(ISODateTimeFormat.dateTimeParser().parseDateTime(mv.releaseTime)), mv.type.toString() });
|
||||
});
|
||||
|
||||
if (minecraftVersionTable.getRowCount() >= 1) {
|
||||
// figure out which row to select
|
||||
int newSelectedRow = 0;
|
||||
if (selectedMinecraftVersion != null) {
|
||||
Optional<VersionManifestVersion> versionToSelect = minecraftVersions.stream()
|
||||
.filter(mv -> mv.id.equals(selectedMinecraftVersion)).findFirst();
|
||||
|
||||
if (versionToSelect.isPresent()) {
|
||||
newSelectedRow = minecraftVersions.indexOf(versionToSelect.get());
|
||||
}
|
||||
}
|
||||
|
||||
minecraftVersionTable.setRowSelectionInterval(newSelectedRow, newSelectedRow);
|
||||
}
|
||||
|
||||
// refresh the table
|
||||
minecraftVersionTable.revalidate();
|
||||
|
||||
// update checkboxes so not all of them can be unchecked
|
||||
minecraftVersionReleasesFilterCheckbox.setEnabled(
|
||||
!(minecraftVersionReleasesFilterCheckbox.isSelected() && minecraftVersionTypeFilters.size() == 1));
|
||||
minecraftVersionExperimentsFilterCheckbox.setEnabled(
|
||||
!(minecraftVersionExperimentsFilterCheckbox.isSelected() && minecraftVersionTypeFilters.size() == 1));
|
||||
minecraftVersionSnapshotsFilterCheckbox.setEnabled(
|
||||
!(minecraftVersionSnapshotsFilterCheckbox.isSelected() && minecraftVersionTypeFilters.size() == 1));
|
||||
minecraftVersionBetasFilterCheckbox.setEnabled(
|
||||
!(minecraftVersionBetasFilterCheckbox.isSelected() && minecraftVersionTypeFilters.size() == 1));
|
||||
minecraftVersionAlphasFilterCheckbox.setEnabled(
|
||||
!(minecraftVersionAlphasFilterCheckbox.isSelected() && minecraftVersionTypeFilters.size() == 1));
|
||||
}
|
||||
|
||||
private void selectedLoaderTypeChanged(LoaderType selectedLoader) {
|
||||
loaderVersionsDropDown.removeAllItems();
|
||||
loaderVersionsDropDown.setEnabled(false);
|
||||
|
||||
if (selectedLoader == null) {
|
||||
// update the name and description fields if they're not dirty
|
||||
String defaultNameFieldValue = String.format("Minecraft %s", selectedMinecraftVersion);
|
||||
if (!nameFieldDirty) {
|
||||
nameField.setText(defaultNameFieldValue);
|
||||
}
|
||||
|
||||
if (!descriptionFieldDirty) {
|
||||
descriptionField.setText(defaultNameFieldValue);
|
||||
}
|
||||
|
||||
loaderVersionsDropDown.addItem(new ComboItem<LoaderVersion>(null, GetText.tr("Select Loader First")));
|
||||
return;
|
||||
}
|
||||
|
||||
loaderVersionsDropDown.addItem(new ComboItem<LoaderVersion>(null, GetText.tr("Getting Loader Versions")));
|
||||
|
||||
loaderTypeNoneRadioButton.setEnabled(false);
|
||||
loaderTypeFabricRadioButton.setEnabled(false);
|
||||
loaderTypeForgeRadioButton.setEnabled(false);
|
||||
loaderTypeLegacyFabricRadioButton.setEnabled(false);
|
||||
loaderTypeQuiltRadioButton.setEnabled(false);
|
||||
loaderVersionsDropDown.setEnabled(false);
|
||||
createServerButton.setEnabled(false);
|
||||
createInstanceButton.setEnabled(false);
|
||||
|
||||
// Legacy Forge doesn't support servers easily
|
||||
boolean enableCreateServers = selectedLoader != LoaderType.FORGE
|
||||
|| !Utils.matchVersion(selectedMinecraftVersion, "1.5", true, true);
|
||||
|
||||
if (ConfigManager.getConfigItem("useGraphql.vanillaLoaderVersions", false) == true) {
|
||||
GraphqlClient.apolloClient.query(new GetLoaderVersionsForMinecraftVersionQuery(selectedMinecraftVersion))
|
||||
.toBuilder()
|
||||
.httpCachePolicy(new HttpCachePolicy.Policy(FetchStrategy.CACHE_FIRST, 5, TimeUnit.MINUTES, false))
|
||||
.build()
|
||||
.enqueue(new ApolloCall.Callback<GetLoaderVersionsForMinecraftVersionQuery.Data>() {
|
||||
@Override
|
||||
public void onResponse(
|
||||
@NotNull Response<GetLoaderVersionsForMinecraftVersionQuery.Data> response) {
|
||||
List<LoaderVersion> loaderVersions = new ArrayList<>();
|
||||
|
||||
if (selectedLoader == LoaderType.FABRIC) {
|
||||
List<String> disabledVersions = ConfigManager.getConfigItem(
|
||||
"loaders.fabric.disabledVersions",
|
||||
new ArrayList<String>());
|
||||
|
||||
loaderVersions.addAll(response.getData().loaderVersions().fabric().stream()
|
||||
.filter(fv -> !disabledVersions.contains(fv.version()))
|
||||
.map(version -> new LoaderVersion(version.version(), false, "Fabric"))
|
||||
.collect(Collectors.toList()));
|
||||
} else if (selectedLoader == LoaderType.FORGE) {
|
||||
List<String> disabledVersions = ConfigManager.getConfigItem(
|
||||
"loaders.forge.disabledVersions",
|
||||
new ArrayList<String>());
|
||||
|
||||
loaderVersions.addAll(response.getData().loaderVersions().forge().stream()
|
||||
.filter(fv -> !disabledVersions.contains(fv.version()))
|
||||
.map(version -> {
|
||||
LoaderVersion lv = new LoaderVersion(version.version(),
|
||||
version.rawVersion(),
|
||||
version.recommended(),
|
||||
"Forge");
|
||||
|
||||
if (version.installerSha1Hash() != null
|
||||
&& version.installerSize() != null) {
|
||||
lv.downloadables.put("installer",
|
||||
new Pair<String, Long>(version.installerSha1Hash(),
|
||||
version.installerSize().longValue()));
|
||||
}
|
||||
|
||||
if (version.universalSha1Hash() != null
|
||||
&& version.universalSize() != null) {
|
||||
lv.downloadables.put("universal",
|
||||
new Pair<String, Long>(version.universalSha1Hash(),
|
||||
version.universalSize().longValue()));
|
||||
}
|
||||
|
||||
if (version.clientSha1Hash() != null && version.clientSize() != null) {
|
||||
lv.downloadables.put("client",
|
||||
new Pair<String, Long>(version.clientSha1Hash(),
|
||||
version.clientSize().longValue()));
|
||||
}
|
||||
|
||||
if (version.serverSha1Hash() != null && version.serverSize() != null) {
|
||||
lv.downloadables.put("server",
|
||||
new Pair<String, Long>(version.serverSha1Hash(),
|
||||
version.serverSize().longValue()));
|
||||
}
|
||||
|
||||
return lv;
|
||||
})
|
||||
.collect(Collectors.toList()));
|
||||
} else if (selectedLoader == LoaderType.LEGACY_FABRIC) {
|
||||
List<String> disabledVersions = ConfigManager.getConfigItem(
|
||||
"loaders.legacyfabric.disabledVersions",
|
||||
new ArrayList<String>());
|
||||
|
||||
loaderVersions.addAll(response.getData().loaderVersions().legacyfabric().stream()
|
||||
.filter(fv -> !disabledVersions.contains(fv.version()))
|
||||
.map(version -> new LoaderVersion(version.version(), false, "LegacyFabric"))
|
||||
.collect(Collectors.toList()));
|
||||
} else if (selectedLoader == LoaderType.QUILT) {
|
||||
List<String> disabledVersions = ConfigManager.getConfigItem(
|
||||
"loaders.quilt.disabledVersions",
|
||||
new ArrayList<String>());
|
||||
|
||||
loaderVersions.addAll(response.getData().loaderVersions().quilt().stream()
|
||||
.filter(fv -> !disabledVersions.contains(fv.version()))
|
||||
.map(version -> new LoaderVersion(version.version(), false, "Quilt"))
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
if (loaderVersions.size() == 0) {
|
||||
loaderVersionsDropDown.removeAllItems();
|
||||
loaderVersionsDropDown
|
||||
.addItem(new ComboItem<LoaderVersion>(null, GetText.tr("No Versions Found")));
|
||||
loaderTypeNoneRadioButton.setEnabled(true);
|
||||
loaderTypeFabricRadioButton.setEnabled(true);
|
||||
loaderTypeForgeRadioButton.setEnabled(true);
|
||||
loaderTypeLegacyFabricRadioButton.setEnabled(true);
|
||||
loaderTypeQuiltRadioButton.setEnabled(true);
|
||||
createServerButton.setEnabled(enableCreateServers);
|
||||
createInstanceButton.setEnabled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
int loaderVersionLength = 0;
|
||||
|
||||
// ensures that font width is taken into account
|
||||
for (LoaderVersion version : loaderVersions) {
|
||||
loaderVersionLength = Math.max(loaderVersionLength,
|
||||
getFontMetrics(App.THEME.getNormalFont()).stringWidth(version.toString()) + 25);
|
||||
}
|
||||
|
||||
loaderVersionsDropDown.removeAllItems();
|
||||
|
||||
loaderVersions.forEach(version -> loaderVersionsDropDown
|
||||
.addItem(new ComboItem<LoaderVersion>(version, version.toString())));
|
||||
|
||||
if (selectedLoader == LoaderType.FORGE) {
|
||||
Optional<LoaderVersion> recommendedVersion = loaderVersions.stream()
|
||||
.filter(lv -> lv.recommended)
|
||||
.findFirst();
|
||||
|
||||
if (recommendedVersion.isPresent()) {
|
||||
loaderVersionsDropDown
|
||||
.setSelectedIndex(loaderVersions.indexOf(recommendedVersion.get()));
|
||||
}
|
||||
}
|
||||
|
||||
// ensures that the dropdown is at least 200 px wide
|
||||
loaderVersionLength = Math.max(200, loaderVersionLength);
|
||||
|
||||
// ensures that there is a maximum width of 400 px to prevent overflow
|
||||
loaderVersionLength = Math.min(400, loaderVersionLength);
|
||||
|
||||
loaderVersionsDropDown.setPreferredSize(new Dimension(loaderVersionLength, 23));
|
||||
|
||||
loaderTypeNoneRadioButton.setEnabled(true);
|
||||
loaderTypeFabricRadioButton.setEnabled(true);
|
||||
loaderTypeForgeRadioButton.setEnabled(true);
|
||||
loaderTypeLegacyFabricRadioButton.setEnabled(true);
|
||||
loaderTypeQuiltRadioButton.setEnabled(true);
|
||||
loaderVersionsDropDown.setEnabled(true);
|
||||
createServerButton.setEnabled(enableCreateServers);
|
||||
createInstanceButton.setEnabled(true);
|
||||
|
||||
// update the name and description fields if they're not dirty
|
||||
String defaultNameFieldValue = String.format("Minecraft %s with %s",
|
||||
selectedMinecraftVersion,
|
||||
selectedLoader.toString());
|
||||
if (!nameFieldDirty) {
|
||||
nameField.setText(defaultNameFieldValue);
|
||||
}
|
||||
|
||||
if (!descriptionFieldDirty) {
|
||||
descriptionField.setText(defaultNameFieldValue);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NotNull ApolloException e) {
|
||||
LogManager.logStackTrace("Error fetching loading versions", e);
|
||||
loaderVersionsDropDown.removeAllItems();
|
||||
loaderVersionsDropDown
|
||||
.addItem(new ComboItem<LoaderVersion>(null, GetText.tr("Error Getting Versions")));
|
||||
loaderTypeNoneRadioButton.setEnabled(true);
|
||||
loaderTypeFabricRadioButton.setEnabled(true);
|
||||
loaderTypeForgeRadioButton.setEnabled(true);
|
||||
loaderTypeLegacyFabricRadioButton.setEnabled(true);
|
||||
loaderTypeQuiltRadioButton.setEnabled(true);
|
||||
createServerButton.setEnabled(enableCreateServers);
|
||||
createInstanceButton.setEnabled(true);
|
||||
return;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
Runnable r = () -> {
|
||||
List<LoaderVersion> loaderVersions = new ArrayList<>();
|
||||
|
||||
if (selectedLoader == LoaderType.FABRIC) {
|
||||
loaderVersions.addAll(FabricLoader.getChoosableVersions(selectedMinecraftVersion));
|
||||
} else if (selectedLoader == LoaderType.FORGE) {
|
||||
loaderVersions.addAll(ForgeLoader.getChoosableVersions(selectedMinecraftVersion));
|
||||
} else if (selectedLoader == LoaderType.LEGACY_FABRIC) {
|
||||
loaderVersions.addAll(LegacyFabricLoader.getChoosableVersions(selectedMinecraftVersion));
|
||||
} else if (selectedLoader == LoaderType.QUILT) {
|
||||
loaderVersions.addAll(QuiltLoader.getChoosableVersions(selectedMinecraftVersion));
|
||||
}
|
||||
|
||||
if (loaderVersions.size() == 0) {
|
||||
loaderVersionsDropDown.removeAllItems();
|
||||
loaderVersionsDropDown.addItem(new ComboItem<LoaderVersion>(null, GetText.tr("No Versions Found")));
|
||||
loaderTypeNoneRadioButton.setEnabled(true);
|
||||
loaderTypeFabricRadioButton.setEnabled(true);
|
||||
loaderTypeForgeRadioButton.setEnabled(true);
|
||||
loaderTypeLegacyFabricRadioButton.setEnabled(true);
|
||||
loaderTypeQuiltRadioButton.setEnabled(true);
|
||||
createServerButton.setEnabled(enableCreateServers);
|
||||
createInstanceButton.setEnabled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
int loaderVersionLength = 0;
|
||||
|
||||
// ensures that font width is taken into account
|
||||
for (LoaderVersion version : loaderVersions) {
|
||||
loaderVersionLength = Math.max(loaderVersionLength,
|
||||
getFontMetrics(App.THEME.getNormalFont()).stringWidth(version.toString()) + 25);
|
||||
}
|
||||
|
||||
loaderVersionsDropDown.removeAllItems();
|
||||
|
||||
loaderVersions.forEach(version -> loaderVersionsDropDown
|
||||
.addItem(new ComboItem<LoaderVersion>(version, version.toString())));
|
||||
|
||||
if (selectedLoader == LoaderType.FORGE) {
|
||||
Optional<LoaderVersion> recommendedVersion = loaderVersions.stream().filter(lv -> lv.recommended)
|
||||
.findFirst();
|
||||
|
||||
if (recommendedVersion.isPresent()) {
|
||||
loaderVersionsDropDown.setSelectedIndex(loaderVersions.indexOf(recommendedVersion.get()));
|
||||
}
|
||||
}
|
||||
|
||||
// ensures that the dropdown is at least 200 px wide
|
||||
loaderVersionLength = Math.max(200, loaderVersionLength);
|
||||
|
||||
// ensures that there is a maximum width of 400 px to prevent overflow
|
||||
loaderVersionLength = Math.min(400, loaderVersionLength);
|
||||
|
||||
loaderVersionsDropDown.setPreferredSize(new Dimension(loaderVersionLength, 23));
|
||||
|
||||
loaderTypeNoneRadioButton.setEnabled(true);
|
||||
loaderTypeFabricRadioButton.setEnabled(true);
|
||||
loaderTypeForgeRadioButton.setEnabled(true);
|
||||
loaderTypeLegacyFabricRadioButton.setEnabled(true);
|
||||
loaderTypeQuiltRadioButton.setEnabled(true);
|
||||
loaderVersionsDropDown.setEnabled(true);
|
||||
createServerButton.setEnabled(enableCreateServers);
|
||||
createInstanceButton.setEnabled(true);
|
||||
|
||||
// update the name and description fields if they're not dirty
|
||||
String defaultNameFieldValue = String.format("Minecraft %s with %s", selectedMinecraftVersion,
|
||||
selectedLoader.toString());
|
||||
if (!nameFieldDirty) {
|
||||
nameField.setText(defaultNameFieldValue);
|
||||
}
|
||||
|
||||
if (!descriptionFieldDirty) {
|
||||
descriptionField.setText(defaultNameFieldValue);
|
||||
}
|
||||
};
|
||||
|
||||
new Thread(r).start();
|
||||
}
|
||||
}
|
||||
|
||||
private void setupBottomPanel() {
|
||||
JPanel bottomPanel = new JPanel(new FlowLayout());
|
||||
|
||||
bottomPanel.add(createServerButton);
|
||||
createServerButton.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
// user has no instances, they may not be aware this is not how to play
|
||||
if (InstanceManager.getInstances().size() == 0) {
|
||||
int ret = DialogManager.yesNoDialog()
|
||||
.setTitle(GetText.tr("Are you sure you want to create a server?"))
|
||||
.setContent(new HTMLBuilder().center().text(GetText.tr(
|
||||
"Creating a server won't allow you play Minecraft, it's for letting others play together.<br/><br/>If you just want to play Minecraft, you don't want to create a server, and instead will want to create an instance.<br/><br/>Are you sure you want to create a server?"))
|
||||
.build())
|
||||
.setType(DialogManager.QUESTION).show();
|
||||
|
||||
if (ret != 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
install(true);
|
||||
}
|
||||
});
|
||||
|
||||
bottomPanel.add(createInstanceButton);
|
||||
createInstanceButton.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
install(false);
|
||||
}
|
||||
});
|
||||
|
||||
add(bottomPanel, BorderLayout.SOUTH);
|
||||
}
|
||||
|
||||
private void install(boolean isServer) {
|
||||
Installable installable;
|
||||
try {
|
||||
LoaderVersion selectedLoaderVersion = ((ComboItem<LoaderVersion>) loaderVersionsDropDown.getSelectedItem())
|
||||
.getValue();
|
||||
|
||||
installable = new VanillaInstallable(MinecraftManager.getMinecraftVersion(selectedMinecraftVersion),
|
||||
selectedLoaderVersion, descriptionField.getText());
|
||||
installable.instanceName = nameField.getText();
|
||||
installable.isReinstall = false;
|
||||
installable.isServer = isServer;
|
||||
|
||||
boolean success = installable.startInstall();
|
||||
|
||||
if (success) {
|
||||
nameFieldDirty = false;
|
||||
descriptionFieldDirty = false;
|
||||
|
||||
loaderTypeNoneRadioButton.setSelected(true);
|
||||
selectedLoaderTypeChanged(null);
|
||||
|
||||
minecraftVersionTable.setRowSelectionInterval(0, 0);
|
||||
}
|
||||
} catch (InvalidMinecraftVersion e) {
|
||||
LogManager.logStackTrace(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return GetText.tr("Vanilla Packs");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAnalyticsScreenViewName() {
|
||||
return "Vanilla Packs";
|
||||
}
|
||||
}
|
|
@ -1,631 +0,0 @@
|
|||
/*
|
||||
* ATLauncher - https://github.com/ATLauncher/ATLauncher
|
||||
* Copyright (C) 2013-2022 ATLauncher
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.atlauncher.gui.tabs
|
||||
|
||||
import com.atlauncher.App
|
||||
import com.atlauncher.builders.HTMLBuilder
|
||||
import com.atlauncher.constants.UIConstants
|
||||
import com.atlauncher.data.MCVersionRow
|
||||
import com.atlauncher.data.minecraft.loaders.LoaderType
|
||||
import com.atlauncher.data.minecraft.loaders.LoaderVersion
|
||||
import com.atlauncher.evnt.listener.RelocalizationListener
|
||||
import com.atlauncher.evnt.manager.RelocalizationManager
|
||||
import com.atlauncher.managers.DialogManager
|
||||
import com.atlauncher.utils.ComboItem
|
||||
import com.atlauncher.viewmodel.base.IVanillaPacksViewModel
|
||||
import com.atlauncher.viewmodel.impl.VanillaPacksViewModel
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
import org.mini2Dx.gettext.GetText
|
||||
import java.awt.*
|
||||
import java.awt.event.ActionEvent
|
||||
import java.awt.event.ActionListener
|
||||
import java.awt.event.KeyAdapter
|
||||
import java.awt.event.KeyEvent
|
||||
import javax.swing.*
|
||||
import javax.swing.event.ListSelectionListener
|
||||
import javax.swing.table.DefaultTableModel
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
class VanillaPacksTab : JPanel(BorderLayout()), Tab, RelocalizationListener {
|
||||
private val nameField = JTextField(32)
|
||||
private val descriptionField = JTextArea(2, 40)
|
||||
|
||||
private fun getReleasesText() = GetText.tr("Releases")
|
||||
private val minecraftVersionReleasesFilterCheckbox = JCheckBox(getReleasesText())
|
||||
|
||||
private fun getExperimentsText() = GetText.tr("Experiments")
|
||||
private val minecraftVersionExperimentsFilterCheckbox = JCheckBox(getExperimentsText())
|
||||
|
||||
private fun getSnapshotsText() = GetText.tr("Snapshots")
|
||||
private val minecraftVersionSnapshotsFilterCheckbox = JCheckBox(getSnapshotsText())
|
||||
|
||||
private fun getBetasText() = GetText.tr("Betas")
|
||||
private val minecraftVersionBetasFilterCheckbox = JCheckBox(getBetasText())
|
||||
|
||||
private fun getAlphasText() = GetText.tr("Alphas")
|
||||
private val minecraftVersionAlphasFilterCheckbox = JCheckBox(getAlphasText())
|
||||
|
||||
private var minecraftVersionTable: JTable? = null
|
||||
private var minecraftVersionTableModel: DefaultTableModel? = null
|
||||
private val loaderTypeButtonGroup = ButtonGroup()
|
||||
|
||||
private fun getNoneText() = GetText.tr("None")
|
||||
private val loaderTypeNoneRadioButton = JRadioButton(getNoneText())
|
||||
private val loaderTypeFabricRadioButton = JRadioButton("Fabric")
|
||||
private val loaderTypeForgeRadioButton = JRadioButton("Forge")
|
||||
private val loaderTypeLegacyFabricRadioButton = JRadioButton("Legacy Fabric")
|
||||
private val loaderTypeQuiltRadioButton = JRadioButton("Quilt")
|
||||
private val loaderVersionsDropDown = JComboBox<ComboItem<LoaderVersion?>>()
|
||||
|
||||
private fun getCreateServerText() = GetText.tr("Create Server")
|
||||
private val createServerButton = JButton(getCreateServerText())
|
||||
|
||||
private fun getCreateInstanceText() = GetText.tr("Create Instance")
|
||||
private val createInstanceButton = JButton(getCreateInstanceText())
|
||||
private val viewModel: IVanillaPacksViewModel = VanillaPacksViewModel()
|
||||
private val scope = CoroutineScope(Dispatchers.Main)
|
||||
|
||||
init {
|
||||
name = "vanillaPacksPanel"
|
||||
setupMainPanel()
|
||||
setupBottomPanel()
|
||||
RelocalizationManager.addListener(this)
|
||||
}
|
||||
|
||||
private fun setupMainPanel() {
|
||||
val mainPanel = JPanel(GridBagLayout())
|
||||
val gbc = GridBagConstraints()
|
||||
|
||||
// Name
|
||||
gbc.gridx = 0
|
||||
gbc.gridy = 0
|
||||
gbc.insets = UIConstants.LABEL_INSETS
|
||||
gbc.anchor = GridBagConstraints.EAST
|
||||
val nameLabel = JLabel(GetText.tr("Instance Name") + ":")
|
||||
mainPanel.add(nameLabel, gbc)
|
||||
gbc.gridx++
|
||||
gbc.insets = UIConstants.FIELD_INSETS
|
||||
gbc.anchor = GridBagConstraints.BASELINE_LEADING
|
||||
scope.launch {
|
||||
viewModel.name.collect {
|
||||
nameField.text = it
|
||||
}
|
||||
}
|
||||
nameField.addKeyListener(object : KeyAdapter() {
|
||||
override fun keyTyped(e: KeyEvent?) {
|
||||
viewModel.setName(nameField.text)
|
||||
}
|
||||
})
|
||||
mainPanel.add(nameField, gbc)
|
||||
|
||||
// Description
|
||||
gbc.gridx = 0
|
||||
gbc.gridy++
|
||||
gbc.insets = UIConstants.LABEL_INSETS
|
||||
gbc.anchor = GridBagConstraints.BASELINE_TRAILING
|
||||
val descriptionLabel = JLabel(GetText.tr("Description") + ":")
|
||||
mainPanel.add(descriptionLabel, gbc)
|
||||
gbc.gridx++
|
||||
gbc.insets = UIConstants.FIELD_INSETS
|
||||
gbc.anchor = GridBagConstraints.BASELINE_LEADING
|
||||
val descriptionScrollPane = JScrollPane(
|
||||
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER
|
||||
)
|
||||
descriptionScrollPane.preferredSize = Dimension(450, 80)
|
||||
descriptionScrollPane.setViewportView(descriptionField)
|
||||
|
||||
scope.launch {
|
||||
viewModel.description.collect {
|
||||
descriptionField.text = it
|
||||
}
|
||||
}
|
||||
descriptionField.addKeyListener(object : KeyAdapter() {
|
||||
override fun keyTyped(e: KeyEvent?) {
|
||||
viewModel.setDescription(descriptionField.text)
|
||||
}
|
||||
})
|
||||
mainPanel.add(descriptionScrollPane, gbc)
|
||||
|
||||
// Minecraft Version
|
||||
gbc.gridx = 0
|
||||
gbc.gridy += 2
|
||||
gbc.insets = UIConstants.LABEL_INSETS
|
||||
gbc.anchor = GridBagConstraints.NORTHEAST
|
||||
val minecraftVersionPanel = JPanel()
|
||||
minecraftVersionPanel.layout = BoxLayout(minecraftVersionPanel, BoxLayout.Y_AXIS)
|
||||
val minecraftVersionLabel = JLabel(GetText.tr("Minecraft Version") + ":")
|
||||
minecraftVersionPanel.add(minecraftVersionLabel)
|
||||
minecraftVersionPanel.add(Box.createVerticalStrut(20))
|
||||
val minecraftVersionFilterPanel = JPanel()
|
||||
minecraftVersionFilterPanel.layout = BoxLayout(minecraftVersionFilterPanel, BoxLayout.Y_AXIS)
|
||||
val minecraftVersionFilterLabel = JLabel(GetText.tr("Filter"))
|
||||
scope.launch {
|
||||
viewModel.font.collect {
|
||||
minecraftVersionFilterLabel.font = it
|
||||
}
|
||||
}
|
||||
minecraftVersionFilterPanel.add(minecraftVersionFilterLabel)
|
||||
|
||||
// Release checkbox
|
||||
setupReleaseCheckbox(minecraftVersionFilterPanel)
|
||||
|
||||
// Experiments checkbox
|
||||
setupExperimentsCheckbox(minecraftVersionFilterPanel)
|
||||
|
||||
// Snapshots checkbox
|
||||
setupSnapshotsCheckbox(minecraftVersionFilterPanel)
|
||||
|
||||
// Old Betas checkbox
|
||||
setupOldBetasCheckbox(minecraftVersionFilterPanel)
|
||||
|
||||
// Old Alphas checkbox
|
||||
setupOldAlphasCheckbox(minecraftVersionFilterPanel)
|
||||
|
||||
minecraftVersionPanel.add(minecraftVersionFilterPanel)
|
||||
mainPanel.add(minecraftVersionPanel, gbc)
|
||||
gbc.gridx++
|
||||
gbc.insets = UIConstants.FIELD_INSETS
|
||||
gbc.anchor = GridBagConstraints.BASELINE_LEADING
|
||||
val minecraftVersionScrollPane = JScrollPane(
|
||||
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER
|
||||
)
|
||||
minecraftVersionScrollPane.preferredSize = Dimension(450, 300)
|
||||
setupMinecraftVersionsTable()
|
||||
minecraftVersionScrollPane.setViewportView(minecraftVersionTable)
|
||||
mainPanel.add(minecraftVersionScrollPane, gbc)
|
||||
|
||||
// Loader Type
|
||||
gbc.gridx = 0
|
||||
gbc.gridy++
|
||||
gbc.insets = UIConstants.LABEL_INSETS
|
||||
gbc.anchor = GridBagConstraints.EAST
|
||||
val loaderTypeLabel = JLabel(GetText.tr("Loader") + "?")
|
||||
mainPanel.add(loaderTypeLabel, gbc)
|
||||
gbc.gridx++
|
||||
gbc.insets = UIConstants.FIELD_INSETS
|
||||
gbc.anchor = GridBagConstraints.BASELINE_LEADING
|
||||
loaderTypeButtonGroup.add(loaderTypeNoneRadioButton)
|
||||
loaderTypeButtonGroup.add(loaderTypeFabricRadioButton)
|
||||
loaderTypeButtonGroup.add(loaderTypeForgeRadioButton)
|
||||
loaderTypeButtonGroup.add(loaderTypeLegacyFabricRadioButton)
|
||||
loaderTypeButtonGroup.add(loaderTypeQuiltRadioButton)
|
||||
val loaderTypePanel = JPanel(FlowLayout())
|
||||
|
||||
setupLoaderNoneButton(loaderTypePanel)
|
||||
|
||||
setupLoaderFabricButton(loaderTypePanel)
|
||||
setupLoaderLegacyFabricButton(loaderTypePanel)
|
||||
|
||||
setupLoaderForgeButton(loaderTypePanel)
|
||||
|
||||
setupLoaderQuiltButton(loaderTypePanel)
|
||||
|
||||
mainPanel.add(loaderTypePanel, gbc)
|
||||
|
||||
// Loader Version
|
||||
gbc.gridx = 0
|
||||
gbc.gridy++
|
||||
gbc.insets = UIConstants.LABEL_INSETS
|
||||
gbc.anchor = GridBagConstraints.BASELINE_TRAILING
|
||||
val loaderVersionLabel = JLabel(GetText.tr("Loader Version") + ":")
|
||||
mainPanel.add(loaderVersionLabel, gbc)
|
||||
gbc.gridx++
|
||||
gbc.insets = UIConstants.FIELD_INSETS
|
||||
gbc.anchor = GridBagConstraints.BASELINE_LEADING
|
||||
scope.launch {
|
||||
viewModel.loaderVersionsDropDownEnabled.collect {
|
||||
loaderVersionsDropDown.isEnabled = it
|
||||
}
|
||||
}
|
||||
scope.launch {
|
||||
viewModel.loaderVersions.collectLatest { loaderVersions ->
|
||||
loaderVersionsDropDown.removeAllItems()
|
||||
if (loaderVersions == null) {
|
||||
setEmpty()
|
||||
} else {
|
||||
var loaderVersionLength = 0
|
||||
|
||||
loaderVersions.forEach { version ->
|
||||
// ensures that font width is taken into account
|
||||
loaderVersionLength = max(
|
||||
loaderVersionLength,
|
||||
getFontMetrics(App.THEME.normalFont)
|
||||
.stringWidth(version.toString()) + 25
|
||||
)
|
||||
|
||||
loaderVersionsDropDown.addItem(
|
||||
ComboItem(
|
||||
version,
|
||||
version.version
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// ensures that the dropdown is at least 200 px wide
|
||||
loaderVersionLength = max(200, loaderVersionLength)
|
||||
|
||||
// ensures that there is a maximum width of 400 px to prevent overflow
|
||||
loaderVersionLength = min(400, loaderVersionLength)
|
||||
loaderVersionsDropDown.preferredSize = Dimension(loaderVersionLength, 23)
|
||||
|
||||
viewModel.selectedLoaderVersion.collect {
|
||||
if (it != null)
|
||||
loaderVersionsDropDown.selectedIndex =
|
||||
loaderVersions.indexOf(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
scope.launch {
|
||||
viewModel.loaderLoading.collect {
|
||||
loaderVersionsDropDown.removeAllItems()
|
||||
if (it) {
|
||||
loaderVersionsDropDown.addItem(ComboItem(null, GetText.tr("Getting Loader Versions")))
|
||||
} else {
|
||||
setEmpty()
|
||||
}
|
||||
}
|
||||
}
|
||||
mainPanel.add(loaderVersionsDropDown, gbc)
|
||||
add(mainPanel, BorderLayout.CENTER)
|
||||
}
|
||||
|
||||
private fun setEmpty() {
|
||||
loaderVersionsDropDown.addItem(ComboItem(null, GetText.tr("Select Loader First")))
|
||||
|
||||
}
|
||||
|
||||
private fun setupLoaderQuiltButton(loaderTypePanel: JPanel) {
|
||||
scope.launch {
|
||||
viewModel.loaderTypeQuiltSelected.collect {
|
||||
loaderTypeQuiltRadioButton.isSelected = it
|
||||
}
|
||||
}
|
||||
scope.launch {
|
||||
viewModel.loaderTypeQuiltEnabled.collect {
|
||||
loaderTypeQuiltRadioButton.isEnabled = it
|
||||
}
|
||||
}
|
||||
scope.launch {
|
||||
viewModel.isQuiltVisible.collect {
|
||||
loaderTypeQuiltRadioButton.isVisible = it
|
||||
}
|
||||
}
|
||||
loaderTypeQuiltRadioButton.addActionListener { e: ActionEvent? ->
|
||||
viewModel.setLoaderType(
|
||||
LoaderType.QUILT
|
||||
)
|
||||
}
|
||||
if (viewModel.showQuiltOption) {
|
||||
loaderTypePanel.add(loaderTypeQuiltRadioButton)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupLoaderForgeButton(loaderTypePanel: JPanel) {
|
||||
scope.launch {
|
||||
viewModel.loaderTypeForgeSelected.collect {
|
||||
loaderTypeForgeRadioButton.isSelected = it
|
||||
}
|
||||
}
|
||||
scope.launch {
|
||||
viewModel.loaderTypeForgeEnabled.collect {
|
||||
loaderTypeForgeRadioButton.isEnabled = it
|
||||
}
|
||||
}
|
||||
scope.launch {
|
||||
viewModel.isForgeVisible.collect {
|
||||
loaderTypeForgeRadioButton.isVisible = it
|
||||
}
|
||||
}
|
||||
loaderTypeForgeRadioButton.addActionListener { e: ActionEvent? ->
|
||||
viewModel.setLoaderType(
|
||||
LoaderType.FORGE
|
||||
)
|
||||
}
|
||||
if (viewModel.showForgeOption) {
|
||||
loaderTypePanel.add(loaderTypeForgeRadioButton)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupLoaderLegacyFabricButton(loaderTypePanel: JPanel) {
|
||||
scope.launch {
|
||||
viewModel.loaderTypeLegacyFabricSelected.collect {
|
||||
loaderTypeLegacyFabricRadioButton.isSelected = it
|
||||
}
|
||||
}
|
||||
scope.launch {
|
||||
viewModel.loaderTypeLegacyFabricEnabled.collect {
|
||||
loaderTypeLegacyFabricRadioButton.isEnabled = it
|
||||
}
|
||||
}
|
||||
scope.launch {
|
||||
viewModel.isLegacyFabricVisible.collect {
|
||||
loaderTypeLegacyFabricRadioButton.isVisible = it
|
||||
}
|
||||
}
|
||||
loaderTypeLegacyFabricRadioButton.addActionListener { e: ActionEvent? ->
|
||||
viewModel.setLoaderType(
|
||||
LoaderType.LEGACY_FABRIC
|
||||
)
|
||||
}
|
||||
if (viewModel.showLegacyFabricOption) {
|
||||
loaderTypePanel.add(loaderTypeLegacyFabricRadioButton)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupLoaderFabricButton(loaderTypePanel: JPanel) {
|
||||
scope.launch {
|
||||
viewModel.loaderTypeFabricSelected.collect {
|
||||
loaderTypeFabricRadioButton.isSelected = it
|
||||
}
|
||||
}
|
||||
scope.launch {
|
||||
viewModel.loaderTypeFabricEnabled.collect {
|
||||
loaderTypeFabricRadioButton.isEnabled = it
|
||||
}
|
||||
}
|
||||
scope.launch {
|
||||
viewModel.isFabricVisible.collect {
|
||||
loaderTypeFabricRadioButton.isVisible = it
|
||||
}
|
||||
}
|
||||
loaderTypeFabricRadioButton.addActionListener { e: ActionEvent? ->
|
||||
viewModel.setLoaderType(
|
||||
LoaderType.FABRIC
|
||||
)
|
||||
}
|
||||
if (viewModel.showFabricOption) {
|
||||
loaderTypePanel.add(loaderTypeFabricRadioButton)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupLoaderNoneButton(loaderTypePanel: JPanel) {
|
||||
scope.launch {
|
||||
viewModel.loaderTypeNoneSelected.collect {
|
||||
loaderTypeNoneRadioButton.isSelected = it
|
||||
}
|
||||
}
|
||||
scope.launch {
|
||||
viewModel.loaderTypeNoneEnabled.collect {
|
||||
loaderTypeNoneRadioButton.isEnabled = it
|
||||
}
|
||||
}
|
||||
loaderTypeNoneRadioButton.addActionListener { e: ActionEvent? ->
|
||||
viewModel.setLoaderType(null)
|
||||
}
|
||||
loaderTypePanel.add(loaderTypeNoneRadioButton)
|
||||
}
|
||||
|
||||
private fun setupOldAlphasCheckbox(minecraftVersionFilterPanel: JPanel) {
|
||||
scope.launch {
|
||||
viewModel.oldAlphaSelected.collect {
|
||||
minecraftVersionAlphasFilterCheckbox.isSelected = it
|
||||
}
|
||||
}
|
||||
scope.launch {
|
||||
viewModel.oldAlphaEnabled.collect {
|
||||
minecraftVersionAlphasFilterCheckbox.isEnabled = it
|
||||
}
|
||||
}
|
||||
minecraftVersionAlphasFilterCheckbox.addActionListener {
|
||||
viewModel.setOldAlphaSelected(minecraftVersionAlphasFilterCheckbox.isSelected)
|
||||
}
|
||||
if (viewModel.showOldAlphaOption) {
|
||||
minecraftVersionFilterPanel.add(minecraftVersionAlphasFilterCheckbox)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupOldBetasCheckbox(minecraftVersionFilterPanel: JPanel) {
|
||||
scope.launch {
|
||||
viewModel.oldBetaSelected.collect {
|
||||
minecraftVersionBetasFilterCheckbox.isSelected = it
|
||||
}
|
||||
}
|
||||
scope.launch {
|
||||
viewModel.oldBetaEnabled.collect {
|
||||
minecraftVersionBetasFilterCheckbox.isEnabled = it
|
||||
}
|
||||
}
|
||||
minecraftVersionBetasFilterCheckbox.addActionListener {
|
||||
viewModel.setOldBetaSelected(minecraftVersionBetasFilterCheckbox.isSelected)
|
||||
}
|
||||
if (viewModel.showOldBetaOption) {
|
||||
minecraftVersionFilterPanel.add(minecraftVersionBetasFilterCheckbox)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupSnapshotsCheckbox(minecraftVersionFilterPanel: JPanel) {
|
||||
scope.launch {
|
||||
viewModel.snapshotSelected.collect {
|
||||
minecraftVersionSnapshotsFilterCheckbox.isSelected = it
|
||||
}
|
||||
}
|
||||
scope.launch {
|
||||
viewModel.snapshotEnabled.collect {
|
||||
minecraftVersionSnapshotsFilterCheckbox.isEnabled = it
|
||||
}
|
||||
}
|
||||
minecraftVersionSnapshotsFilterCheckbox.addActionListener {
|
||||
viewModel.setSnapshotSelected(minecraftVersionSnapshotsFilterCheckbox.isSelected)
|
||||
}
|
||||
if (viewModel.showSnapshotOption) {
|
||||
minecraftVersionFilterPanel.add(minecraftVersionSnapshotsFilterCheckbox)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupExperimentsCheckbox(minecraftVersionFilterPanel: JPanel) {
|
||||
scope.launch {
|
||||
viewModel.experimentSelected.collect {
|
||||
minecraftVersionExperimentsFilterCheckbox.isSelected = it
|
||||
}
|
||||
}
|
||||
scope.launch {
|
||||
viewModel.experimentEnabled.collect {
|
||||
minecraftVersionExperimentsFilterCheckbox.isEnabled = it
|
||||
}
|
||||
}
|
||||
minecraftVersionExperimentsFilterCheckbox.addActionListener {
|
||||
viewModel.setExperimentSelected(minecraftVersionExperimentsFilterCheckbox.isSelected)
|
||||
}
|
||||
if (viewModel.showExperimentOption) {
|
||||
minecraftVersionFilterPanel.add(minecraftVersionExperimentsFilterCheckbox)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupReleaseCheckbox(minecraftVersionFilterPanel: JPanel) {
|
||||
scope.launch {
|
||||
viewModel.releaseSelected.collect {
|
||||
minecraftVersionReleasesFilterCheckbox.isSelected = it
|
||||
}
|
||||
}
|
||||
scope.launch {
|
||||
viewModel.releaseEnabled.collect {
|
||||
minecraftVersionReleasesFilterCheckbox.isEnabled = it
|
||||
}
|
||||
}
|
||||
minecraftVersionReleasesFilterCheckbox.isSelected = true
|
||||
minecraftVersionReleasesFilterCheckbox.addActionListener {
|
||||
viewModel.setReleaseSelected(minecraftVersionReleasesFilterCheckbox.isSelected)
|
||||
}
|
||||
if (viewModel.showReleaseOption) {
|
||||
minecraftVersionFilterPanel.add(minecraftVersionReleasesFilterCheckbox)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupMinecraftVersionsTable() {
|
||||
minecraftVersionTableModel = object : DefaultTableModel(
|
||||
arrayOf<Array<String>>(), arrayOf(GetText.tr("Version"), GetText.tr("Released"), GetText.tr("Type"))
|
||||
) {
|
||||
override fun isCellEditable(rowIndex: Int, columnIndex: Int): Boolean {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
minecraftVersionTable = JTable(minecraftVersionTableModel)
|
||||
minecraftVersionTable!!.tableHeader.reorderingAllowed = false
|
||||
val sm = minecraftVersionTable!!.selectionModel
|
||||
sm.addListSelectionListener(ListSelectionListener { e ->
|
||||
if (e.valueIsAdjusting) {
|
||||
return@ListSelectionListener
|
||||
}
|
||||
val lsm = e.source as ListSelectionModel
|
||||
|
||||
val minIndex = e.firstIndex
|
||||
val maxIndex = e.lastIndex
|
||||
for (i in minIndex..maxIndex) {
|
||||
if (lsm.isSelectedIndex(i)) {
|
||||
viewModel.setSelectedMinecraftVersion(
|
||||
minecraftVersionTableModel!!.getValueAt(
|
||||
i, 0
|
||||
) as String
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
scope.launch {
|
||||
viewModel.minecraftVersions.collectLatest { minecraftVersions ->
|
||||
|
||||
// remove all rows
|
||||
val rowCount = minecraftVersionTableModel?.rowCount ?: 0
|
||||
if (rowCount > 0) {
|
||||
for (i in rowCount - 1 downTo 0) {
|
||||
minecraftVersionTableModel?.removeRow(i)
|
||||
}
|
||||
}
|
||||
|
||||
minecraftVersions.forEach { row: MCVersionRow ->
|
||||
minecraftVersionTableModel?.addRow(
|
||||
arrayOf(
|
||||
row.id,
|
||||
row.date,
|
||||
row.type
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// refresh the table
|
||||
minecraftVersionTable?.revalidate()
|
||||
}
|
||||
}
|
||||
scope.launch {
|
||||
viewModel.selectedMinecraftVersionIndex.collect {
|
||||
if (it < (minecraftVersionTable?.rowCount ?: 0)) {
|
||||
minecraftVersionTable?.setRowSelectionInterval(it, it)
|
||||
minecraftVersionTable?.revalidate()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val cm = minecraftVersionTable!!.columnModel
|
||||
cm.getColumn(0).resizable = false
|
||||
cm.getColumn(1).resizable = false
|
||||
cm.getColumn(1).maxWidth = 200
|
||||
cm.getColumn(2).resizable = false
|
||||
cm.getColumn(2).maxWidth = 200
|
||||
minecraftVersionTable!!.setSelectionMode(ListSelectionModel.SINGLE_SELECTION)
|
||||
minecraftVersionTable!!.showVerticalLines = false
|
||||
}
|
||||
|
||||
private fun setupBottomPanel() {
|
||||
val bottomPanel = JPanel(FlowLayout())
|
||||
bottomPanel.add(createServerButton)
|
||||
createServerButton.addActionListener(ActionListener { // user has no instances, they may not be aware this is not how to play
|
||||
if (viewModel.warnUserAboutServer) {
|
||||
val ret = DialogManager.yesNoDialog().setTitle(GetText.tr("Are you sure you want to create a server?"))
|
||||
.setContent(
|
||||
HTMLBuilder().center().text(
|
||||
GetText.tr(
|
||||
"Creating a server won't allow you play Minecraft, it's for letting others play together.<br/><br/>If you just want to play Minecraft, you don't want to create a server, and instead will want to create an instance.<br/><br/>Are you sure you want to create a server?"
|
||||
)
|
||||
).build()
|
||||
).setType(DialogManager.QUESTION).show()
|
||||
if (ret != 0) {
|
||||
return@ActionListener
|
||||
}
|
||||
}
|
||||
viewModel.createServer()
|
||||
})
|
||||
bottomPanel.add(createInstanceButton)
|
||||
createInstanceButton.addActionListener { viewModel.createInstance() }
|
||||
add(bottomPanel, BorderLayout.SOUTH)
|
||||
}
|
||||
|
||||
override fun getTitle(): String {
|
||||
return GetText.tr("Vanilla Packs")
|
||||
}
|
||||
|
||||
override fun getAnalyticsScreenViewName(): String {
|
||||
return "Vanilla Packs"
|
||||
}
|
||||
|
||||
override fun onRelocalization() {
|
||||
minecraftVersionReleasesFilterCheckbox.text = getReleasesText()
|
||||
minecraftVersionExperimentsFilterCheckbox.text = getExperimentsText()
|
||||
minecraftVersionSnapshotsFilterCheckbox.text = getSnapshotsText()
|
||||
minecraftVersionBetasFilterCheckbox.text = getBetasText()
|
||||
minecraftVersionAlphasFilterCheckbox.text = getAlphasText()
|
||||
loaderTypeNoneRadioButton.text = getNoneText()
|
||||
createServerButton.text = getCreateServerText()
|
||||
createInstanceButton.text = getCreateInstanceText()
|
||||
}
|
||||
|
||||
}
|
|
@ -1,336 +0,0 @@
|
|||
/*
|
||||
* ATLauncher - https://github.com/ATLauncher/ATLauncher
|
||||
* Copyright (C) 2013-2022 ATLauncher
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.atlauncher.viewmodel.base
|
||||
|
||||
import com.atlauncher.data.MCVersionRow
|
||||
import com.atlauncher.data.minecraft.loaders.LoaderType
|
||||
import com.atlauncher.data.minecraft.loaders.LoaderVersion
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import java.awt.Font
|
||||
|
||||
/**
|
||||
* 25 / 06 / 2022
|
||||
*/
|
||||
interface IVanillaPacksViewModel {
|
||||
// UI settings
|
||||
/**
|
||||
* Controls what font to use
|
||||
*/
|
||||
val font: Flow<Font>
|
||||
|
||||
// Pack Options
|
||||
|
||||
/**
|
||||
* Name of the new instance
|
||||
*/
|
||||
val name: Flow<String?>
|
||||
|
||||
/**
|
||||
* Set the name of the new instance
|
||||
*/
|
||||
fun setName(name: String)
|
||||
|
||||
/**
|
||||
* Description of the new instance
|
||||
*/
|
||||
val description: Flow<String?>
|
||||
|
||||
/**
|
||||
* Set the new description of the new instance
|
||||
*/
|
||||
fun setDescription(description: String)
|
||||
|
||||
// Release Options
|
||||
|
||||
/**
|
||||
* If the release checkbox should be visible
|
||||
*/
|
||||
val showReleaseOption: Boolean
|
||||
|
||||
/**
|
||||
* If the experiment checkbox should be visible
|
||||
*/
|
||||
val showExperimentOption: Boolean
|
||||
|
||||
/**
|
||||
* If the snapshot checkbox should be visible
|
||||
*/
|
||||
val showSnapshotOption: Boolean
|
||||
|
||||
/**
|
||||
* If the old alpha option should be visible
|
||||
*/
|
||||
val showOldAlphaOption: Boolean
|
||||
|
||||
/**
|
||||
* If the old beta option should be visible
|
||||
*/
|
||||
val showOldBetaOption: Boolean
|
||||
|
||||
/**
|
||||
* Is the release checkbox selected
|
||||
*/
|
||||
val releaseSelected: Flow<Boolean>
|
||||
|
||||
/**
|
||||
* Is the release checkbox enabled
|
||||
*/
|
||||
val releaseEnabled: Flow<Boolean>
|
||||
|
||||
/**
|
||||
* Is the experiment checkbox selected
|
||||
*/
|
||||
val experimentSelected: Flow<Boolean>
|
||||
|
||||
/**
|
||||
* Is the experiment checkbox enabled
|
||||
*/
|
||||
val experimentEnabled: Flow<Boolean>
|
||||
|
||||
/**
|
||||
* Is the snapshot checkbox selected
|
||||
*/
|
||||
val snapshotSelected: Flow<Boolean>
|
||||
|
||||
/**
|
||||
* Is the snapshot checkbox enabled
|
||||
*/
|
||||
val snapshotEnabled: Flow<Boolean>
|
||||
|
||||
/**
|
||||
* Is the alpha checkbox selected
|
||||
*/
|
||||
val oldAlphaSelected: Flow<Boolean>
|
||||
|
||||
/**
|
||||
* Is the alpha checkbox enabled
|
||||
*/
|
||||
val oldAlphaEnabled: Flow<Boolean>
|
||||
|
||||
/**
|
||||
* Is the beta checkbox selected
|
||||
*/
|
||||
val oldBetaSelected: Flow<Boolean>
|
||||
|
||||
/**
|
||||
* Is the beta checkbox enabled
|
||||
*/
|
||||
val oldBetaEnabled: Flow<Boolean>
|
||||
|
||||
/**
|
||||
* Set [releaseSelected] or not
|
||||
*
|
||||
* Should reload [minecraftVersions]
|
||||
*/
|
||||
fun setReleaseSelected(b: Boolean)
|
||||
|
||||
/**
|
||||
* Set [experimentSelected] or not
|
||||
*
|
||||
* Should reload [minecraftVersions]
|
||||
*/
|
||||
fun setExperimentSelected(b: Boolean)
|
||||
|
||||
/**
|
||||
* Set [snapshotSelected] or not
|
||||
*
|
||||
* Should reload [minecraftVersions]
|
||||
*/
|
||||
fun setSnapshotSelected(b: Boolean)
|
||||
|
||||
/**
|
||||
* Set [oldAlphaSelected] or not
|
||||
*
|
||||
* Should reload [minecraftVersions]
|
||||
*/
|
||||
fun setOldAlphaSelected(b: Boolean)
|
||||
|
||||
/**
|
||||
* Set [oldBetaSelected] or not
|
||||
*
|
||||
* Should reload [minecraftVersions]
|
||||
*/
|
||||
fun setOldBetaSelected(b: Boolean)
|
||||
|
||||
/**
|
||||
* Minecraft versions to display in the version table
|
||||
*/
|
||||
val minecraftVersions: Flow<Array<MCVersionRow>>
|
||||
|
||||
/**
|
||||
* Which index is currently selected
|
||||
*/
|
||||
val selectedMinecraftVersionIndex: Flow<Int>
|
||||
|
||||
/**
|
||||
* Set the selected minecraft version
|
||||
*/
|
||||
fun setSelectedMinecraftVersion(valueAt: String?)
|
||||
|
||||
// Mod loader option
|
||||
|
||||
/**
|
||||
* Is fabric an option currently
|
||||
*/
|
||||
val isFabricVisible: Flow<Boolean>
|
||||
|
||||
/**
|
||||
* Is legacy fabric an option currently
|
||||
*/
|
||||
val isLegacyFabricVisible: Flow<Boolean>
|
||||
|
||||
/**
|
||||
* Is forge an option currently
|
||||
*/
|
||||
val isForgeVisible: Flow<Boolean>
|
||||
|
||||
/**
|
||||
* Is quilt an option currently
|
||||
*/
|
||||
val isQuiltVisible: Flow<Boolean>
|
||||
|
||||
/**
|
||||
* If fabric is enabled in config or not
|
||||
*/
|
||||
val showFabricOption: Boolean
|
||||
|
||||
/**
|
||||
* If forge is enabled in config or not
|
||||
*/
|
||||
val showForgeOption: Boolean
|
||||
|
||||
/**
|
||||
* If legacy forge should be enabled or not
|
||||
*/
|
||||
val showLegacyFabricOption: Boolean
|
||||
|
||||
/**
|
||||
* If quilt is enabled in config or not
|
||||
*/
|
||||
val showQuiltOption: Boolean
|
||||
|
||||
/**
|
||||
* Has none been selected
|
||||
*/
|
||||
val loaderTypeNoneSelected: Flow<Boolean>
|
||||
|
||||
/**
|
||||
* Is the none button enabled or not
|
||||
*/
|
||||
val loaderTypeNoneEnabled: Flow<Boolean>
|
||||
|
||||
/**
|
||||
* Has fabric been selected
|
||||
*/
|
||||
val loaderTypeFabricSelected: Flow<Boolean>
|
||||
|
||||
/**
|
||||
* Is the fabric button enabled or not
|
||||
*/
|
||||
val loaderTypeFabricEnabled: Flow<Boolean>
|
||||
|
||||
/**
|
||||
* Has forge been selected
|
||||
*/
|
||||
val loaderTypeForgeSelected: Flow<Boolean>
|
||||
|
||||
/**
|
||||
* Is legacy fabric selected
|
||||
*/
|
||||
val loaderTypeLegacyFabricSelected: Flow<Boolean>
|
||||
|
||||
/**
|
||||
* Is the forge button enabled or not
|
||||
*/
|
||||
val loaderTypeForgeEnabled: Flow<Boolean>
|
||||
|
||||
/**
|
||||
* Is legacy fabric enabled
|
||||
*/
|
||||
val loaderTypeLegacyFabricEnabled: Flow<Boolean>
|
||||
|
||||
/**
|
||||
* Has quilt been selected
|
||||
*/
|
||||
val loaderTypeQuiltSelected: Flow<Boolean>
|
||||
|
||||
/**
|
||||
* Is the quilt button enabled or not
|
||||
*/
|
||||
val loaderTypeQuiltEnabled: Flow<Boolean>
|
||||
|
||||
/**
|
||||
* Set the loader type
|
||||
*
|
||||
* Will cause a reload of [loaderVersions]
|
||||
*/
|
||||
fun setLoaderType(loader: LoaderType?)
|
||||
|
||||
/**
|
||||
* Set the selected loader version
|
||||
*/
|
||||
fun setLoaderVersion(loaderVersion: String)
|
||||
|
||||
/**
|
||||
* Is the loader versions drop down enabled
|
||||
*/
|
||||
val loaderVersionsDropDownEnabled: Flow<Boolean>
|
||||
|
||||
/**
|
||||
* Loader versions that the user can select for the loaderType
|
||||
*/
|
||||
val loaderVersions: Flow<Array<LoaderVersion>?>
|
||||
|
||||
|
||||
/**
|
||||
* The selected mod loader version
|
||||
*/
|
||||
val selectedLoaderVersion: Flow<LoaderVersion?>
|
||||
|
||||
/**
|
||||
* Is the loader loading.
|
||||
*
|
||||
* This value is used to show a little loading icon
|
||||
*/
|
||||
val loaderLoading: Flow<Boolean>
|
||||
|
||||
/**
|
||||
* Is the create server button enabled or not
|
||||
*/
|
||||
val createServerEnabled: Flow<Boolean>
|
||||
|
||||
/**
|
||||
* Is the create instance button enabled or not
|
||||
*/
|
||||
val createInstanceEnabled: Flow<Boolean>
|
||||
|
||||
/**
|
||||
* Create a server with the provided information
|
||||
*/
|
||||
fun createServer()
|
||||
|
||||
/**
|
||||
* Create an instance with the provided information
|
||||
*/
|
||||
fun createInstance()
|
||||
|
||||
/**
|
||||
* Warn the user about creating a server =/= playing the game themselves
|
||||
*/
|
||||
val warnUserAboutServer: Boolean
|
||||
}
|
|
@ -1,676 +0,0 @@
|
|||
/*
|
||||
* ATLauncher - https://github.com/ATLauncher/ATLauncher
|
||||
* Copyright (C) 2013-2022 ATLauncher
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.atlauncher.viewmodel.impl
|
||||
|
||||
import com.apollographql.apollo.api.cache.http.HttpCachePolicy
|
||||
import com.apollographql.apollo.coroutines.await
|
||||
import com.apollographql.apollo.exception.ApolloException
|
||||
import com.atlauncher.App
|
||||
import com.atlauncher.data.installables.Installable
|
||||
import com.atlauncher.data.installables.VanillaInstallable
|
||||
import com.atlauncher.data.minecraft.VersionManifestVersion
|
||||
import com.atlauncher.data.minecraft.VersionManifestVersionType
|
||||
import com.atlauncher.data.minecraft.loaders.LoaderType
|
||||
import com.atlauncher.data.minecraft.loaders.LoaderVersion
|
||||
import com.atlauncher.data.minecraft.loaders.fabric.FabricLoader
|
||||
import com.atlauncher.data.minecraft.loaders.forge.ForgeLoader
|
||||
import com.atlauncher.data.minecraft.loaders.legacyfabric.LegacyFabricLoader
|
||||
import com.atlauncher.data.minecraft.loaders.quilt.QuiltLoader
|
||||
import com.atlauncher.evnt.listener.SettingsListener
|
||||
import com.atlauncher.evnt.manager.SettingsManager
|
||||
import com.atlauncher.exceptions.InvalidMinecraftVersion
|
||||
import com.atlauncher.graphql.GetLoaderVersionsForMinecraftVersionQuery
|
||||
import com.atlauncher.managers.ConfigManager
|
||||
import com.atlauncher.managers.InstanceManager
|
||||
import com.atlauncher.managers.LogManager
|
||||
import com.atlauncher.managers.MinecraftManager
|
||||
import com.atlauncher.network.GraphqlClient
|
||||
import com.atlauncher.utils.Pair
|
||||
import com.atlauncher.utils.Utils
|
||||
import com.atlauncher.viewmodel.base.IVanillaPacksViewModel
|
||||
import com.atlauncher.data.MCVersionRow
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.launch
|
||||
import org.joda.time.format.DateTimeFormat
|
||||
import org.joda.time.format.ISODateTimeFormat
|
||||
import org.mini2Dx.gettext.GetText
|
||||
import java.awt.Font
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.util.stream.Collectors
|
||||
|
||||
|
||||
/**
|
||||
* 25 / 06 / 2022
|
||||
*/
|
||||
class VanillaPacksViewModel : IVanillaPacksViewModel, SettingsListener {
|
||||
private val scope = CoroutineScope(Dispatchers.IO)
|
||||
|
||||
/**
|
||||
* Filters applied to the version table
|
||||
*/
|
||||
private val minecraftVersionTypeFiltersFlow = MutableStateFlow(mapOf(VersionManifestVersionType.RELEASE to true))
|
||||
|
||||
/**
|
||||
* Name is dirty, as the user has inputted something
|
||||
*/
|
||||
private var nameDirty = false
|
||||
|
||||
/**
|
||||
* Name to display
|
||||
*/
|
||||
override val name = MutableStateFlow<String?>(null)
|
||||
|
||||
/**
|
||||
* Description is dirty, as the user has inputted something
|
||||
*/
|
||||
private var descriptionDirty = false
|
||||
|
||||
/**
|
||||
* Description to display
|
||||
*/
|
||||
override val description = MutableStateFlow<String?>(null)
|
||||
|
||||
private val selectedMinecraftVersionFlow = MutableStateFlow<String?>(null)
|
||||
override val selectedMinecraftVersionIndex: Flow<Int> by lazy {
|
||||
minecraftVersions.combine(selectedMinecraftVersionFlow) { versions, version ->
|
||||
val index = versions.indexOfFirst { it.id == version }
|
||||
if (index == -1) return@combine 0
|
||||
return@combine index
|
||||
}
|
||||
}
|
||||
private val selectedLoaderType = MutableStateFlow<LoaderType?>(null)
|
||||
|
||||
override val selectedLoaderVersion = MutableStateFlow<LoaderVersion?>(null)
|
||||
|
||||
override val loaderLoading = MutableStateFlow(false)
|
||||
|
||||
override val font = MutableStateFlow<Font>(App.THEME.boldFont)
|
||||
|
||||
// Consumers
|
||||
/**
|
||||
* Represents the version list
|
||||
*/
|
||||
override val minecraftVersions: Flow<Array<MCVersionRow>> by lazy {
|
||||
minecraftVersionTypeFiltersFlow.map { versionFilter: Map<VersionManifestVersionType, Boolean> ->
|
||||
val filtered = versionFilter.filter { it.value }.map { it.key }.toList()
|
||||
val fmt = DateTimeFormat.forPattern(App.settings.dateFormat)
|
||||
|
||||
MinecraftManager.getFilteredMinecraftVersions(filtered).map { it: VersionManifestVersion ->
|
||||
MCVersionRow(
|
||||
it.id, fmt.print(ISODateTimeFormat.dateTimeParser().parseDateTime(it.releaseTime)), it.id
|
||||
)
|
||||
}.toTypedArray()
|
||||
}
|
||||
}
|
||||
|
||||
override val loaderVersionsDropDownEnabled = MutableStateFlow(false)
|
||||
|
||||
/**
|
||||
* Presents the loader versions for the user to select
|
||||
*/
|
||||
override val loaderVersions = MutableStateFlow<Array<LoaderVersion>?>(null)
|
||||
|
||||
override val createServerEnabled = MutableStateFlow(false)
|
||||
override val createInstanceEnabled = MutableStateFlow(false)
|
||||
|
||||
override val isFabricVisible by lazy {
|
||||
selectedMinecraftVersionFlow.map { version ->
|
||||
!fabricDisabledMCVersions.contains(version)
|
||||
}
|
||||
}
|
||||
|
||||
override val isLegacyFabricVisible: Flow<Boolean> by lazy {
|
||||
selectedMinecraftVersionFlow.map { version ->
|
||||
!legacyFabricDisabledMCVersions.contains(version)
|
||||
}
|
||||
}
|
||||
|
||||
override val isForgeVisible by lazy {
|
||||
selectedMinecraftVersionFlow.map { version ->
|
||||
!forgeDisabledMCVersions.contains(version)
|
||||
}
|
||||
}
|
||||
|
||||
override val isQuiltVisible by lazy {
|
||||
selectedMinecraftVersionFlow.map { version ->
|
||||
!quiltDisabledMCVersions.contains(version)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override val loaderTypeFabricSelected: Flow<Boolean> = selectedLoaderType.map {
|
||||
it == LoaderType.FABRIC
|
||||
}
|
||||
override val loaderTypeFabricEnabled = MutableStateFlow(true)
|
||||
|
||||
override val loaderTypeForgeSelected: Flow<Boolean> = selectedLoaderType.map {
|
||||
it == LoaderType.FORGE
|
||||
}
|
||||
override val loaderTypeLegacyFabricSelected: Flow<Boolean> =
|
||||
selectedLoaderType.map {
|
||||
it == LoaderType.LEGACY_FABRIC
|
||||
}
|
||||
override val loaderTypeForgeEnabled = MutableStateFlow(true)
|
||||
override val loaderTypeLegacyFabricEnabled = MutableStateFlow(true)
|
||||
|
||||
override val loaderTypeNoneSelected: Flow<Boolean> = selectedLoaderType.map {
|
||||
it == null
|
||||
}
|
||||
override val loaderTypeNoneEnabled = MutableStateFlow(true)
|
||||
|
||||
override val loaderTypeQuiltSelected: Flow<Boolean> = selectedLoaderType.map {
|
||||
it == LoaderType.QUILT
|
||||
}
|
||||
override val loaderTypeQuiltEnabled = MutableStateFlow(true)
|
||||
|
||||
/**
|
||||
* Just a small copy function, to copy the values of a map.
|
||||
*
|
||||
* This is useful for flows, as a map is considered a persistent structure.
|
||||
* Thus, modifications to the map doesn't "change" the map.
|
||||
*/
|
||||
private fun <K, V> Map<K, V>.copy(): Map<K, V> {
|
||||
val map = HashMap<K, V>()
|
||||
this.forEach { (k, v) ->
|
||||
map[k] = v
|
||||
}
|
||||
return map
|
||||
}
|
||||
|
||||
private fun install(isServer: Boolean) {
|
||||
val installable: Installable
|
||||
try {
|
||||
val selectedLoaderVersion = selectedLoaderVersion.value
|
||||
val selectedMinecraftVersion = selectedMinecraftVersionFlow.value ?: return
|
||||
val description = description.value
|
||||
val name = name.value
|
||||
|
||||
installable = VanillaInstallable(
|
||||
MinecraftManager.getMinecraftVersion(selectedMinecraftVersion),
|
||||
selectedLoaderVersion,
|
||||
description
|
||||
)
|
||||
installable.instanceName = name
|
||||
installable.isReinstall = false
|
||||
installable.isServer = isServer
|
||||
val success = installable.startInstall()
|
||||
if (success) {
|
||||
// - Reset the view, currently disabled
|
||||
//nameFieldDirty = false
|
||||
//descriptionFieldDirty = false
|
||||
//loaderTypeNoneRadioButton.isSelected = true
|
||||
//selectedLoaderTypeChanged(null)
|
||||
//minecraftVersionTable!!.setRowSelectionInterval(0, 0)
|
||||
}
|
||||
} catch (e: InvalidMinecraftVersion) {
|
||||
LogManager.logStackTrace(e)
|
||||
}
|
||||
}
|
||||
|
||||
private fun isNameDirty() = !(name.value == String.format(
|
||||
"Minecraft %s", selectedMinecraftVersionFlow.value
|
||||
) || selectedLoaderType.value != null && name.value == String.format(
|
||||
"Minecraft %s with %s", selectedMinecraftVersionFlow.value, selectedLoaderType.value
|
||||
))
|
||||
|
||||
override fun setName(name: String) {
|
||||
LogManager.debug("setName $name")
|
||||
this.name.value = (name)
|
||||
nameDirty = isNameDirty()
|
||||
}
|
||||
|
||||
private fun isDescriptionDirty() = !(description.value == String.format(
|
||||
"Minecraft %s", selectedMinecraftVersionFlow.value
|
||||
) || selectedLoaderType.value != null && description.value == String.format(
|
||||
"Minecraft %s with %s", selectedMinecraftVersionFlow.value, selectedLoaderType.value
|
||||
))
|
||||
|
||||
override fun setDescription(description: String) {
|
||||
descriptionDirty = isDescriptionDirty()
|
||||
this.description.value = (description)
|
||||
}
|
||||
|
||||
override val showReleaseOption: Boolean by lazy { ConfigManager.getConfigItem("minecraft.release.enabled", true) }
|
||||
|
||||
override val showExperimentOption: Boolean by lazy {
|
||||
ConfigManager.getConfigItem(
|
||||
"minecraft.experiment.enabled",
|
||||
true
|
||||
)
|
||||
}
|
||||
|
||||
override val showSnapshotOption: Boolean by lazy { ConfigManager.getConfigItem("minecraft.snapshot.enabled", true) }
|
||||
|
||||
override val showOldAlphaOption: Boolean by lazy {
|
||||
ConfigManager.getConfigItem(
|
||||
"minecraft.old_alpha.enabled",
|
||||
true
|
||||
)
|
||||
}
|
||||
|
||||
override val showOldBetaOption: Boolean by lazy { ConfigManager.getConfigItem("minecraft.old_beta.enabled", true) }
|
||||
|
||||
override fun setReleaseSelected(b: Boolean) {
|
||||
val map = HashMap(minecraftVersionTypeFiltersFlow.value)
|
||||
map[VersionManifestVersionType.RELEASE] = b
|
||||
minecraftVersionTypeFiltersFlow.value = map.copy()
|
||||
}
|
||||
|
||||
override val releaseSelected: Flow<Boolean> = minecraftVersionTypeFiltersFlow.map {
|
||||
it[VersionManifestVersionType.RELEASE] ?: false
|
||||
}
|
||||
|
||||
override val releaseEnabled: Flow<Boolean> = releaseSelected.combine(minecraftVersionTypeFiltersFlow) { a, b ->
|
||||
!(a && (b.count { it.value } == 1))
|
||||
}
|
||||
|
||||
override fun setExperimentSelected(b: Boolean) {
|
||||
val map = HashMap(minecraftVersionTypeFiltersFlow.value)
|
||||
map[VersionManifestVersionType.EXPERIMENT] = b
|
||||
minecraftVersionTypeFiltersFlow.value = map.copy()
|
||||
}
|
||||
|
||||
override val experimentSelected: Flow<Boolean> = minecraftVersionTypeFiltersFlow.map {
|
||||
it[VersionManifestVersionType.EXPERIMENT] ?: false
|
||||
}
|
||||
|
||||
override val experimentEnabled: Flow<Boolean> =
|
||||
experimentSelected.combine(minecraftVersionTypeFiltersFlow) { a, b ->
|
||||
!(a && (b.count { it.value } == 1))
|
||||
}
|
||||
|
||||
override fun setSnapshotSelected(b: Boolean) {
|
||||
val map = HashMap(minecraftVersionTypeFiltersFlow.value)
|
||||
map[VersionManifestVersionType.SNAPSHOT] = b
|
||||
minecraftVersionTypeFiltersFlow.value = map.copy()
|
||||
}
|
||||
|
||||
override val snapshotSelected: Flow<Boolean> = minecraftVersionTypeFiltersFlow.map {
|
||||
it[VersionManifestVersionType.SNAPSHOT] ?: false
|
||||
}
|
||||
|
||||
override val snapshotEnabled: Flow<Boolean> = snapshotSelected.combine(minecraftVersionTypeFiltersFlow) { a, b ->
|
||||
!(a && (b.count { it.value } == 1))
|
||||
}
|
||||
|
||||
override fun setOldAlphaSelected(b: Boolean) {
|
||||
val map = HashMap(minecraftVersionTypeFiltersFlow.value)
|
||||
map[VersionManifestVersionType.OLD_ALPHA] = b
|
||||
minecraftVersionTypeFiltersFlow.value = map.copy()
|
||||
}
|
||||
|
||||
override val oldAlphaSelected: Flow<Boolean> = minecraftVersionTypeFiltersFlow.map {
|
||||
it[VersionManifestVersionType.OLD_ALPHA] ?: false
|
||||
}
|
||||
|
||||
override val oldAlphaEnabled: Flow<Boolean> = oldAlphaSelected.combine(minecraftVersionTypeFiltersFlow) { a, b ->
|
||||
!(a && (b.count { it.value } == 1))
|
||||
}
|
||||
|
||||
override fun setOldBetaSelected(b: Boolean) {
|
||||
val map = HashMap(minecraftVersionTypeFiltersFlow.value)
|
||||
map[VersionManifestVersionType.OLD_BETA] = b
|
||||
minecraftVersionTypeFiltersFlow.value = map.copy()
|
||||
}
|
||||
|
||||
override val oldBetaSelected: Flow<Boolean> = minecraftVersionTypeFiltersFlow.map {
|
||||
it[VersionManifestVersionType.OLD_BETA] ?: false
|
||||
}
|
||||
|
||||
override val oldBetaEnabled: Flow<Boolean> = oldBetaSelected.combine(minecraftVersionTypeFiltersFlow) { a, b ->
|
||||
!(a && (b.count { it.value } == 1))
|
||||
}
|
||||
|
||||
override fun setSelectedMinecraftVersion(newVersion: String?) {
|
||||
selectedMinecraftVersionFlow.value = newVersion
|
||||
}
|
||||
|
||||
override val showFabricOption: Boolean by lazy { ConfigManager.getConfigItem("loaders.fabric.enabled", true) }
|
||||
|
||||
override val showForgeOption: Boolean by lazy { ConfigManager.getConfigItem("loaders.forge.enabled", true) }
|
||||
override val showLegacyFabricOption: Boolean by lazy {
|
||||
ConfigManager.getConfigItem(
|
||||
"loaders.legacyfabric.enabled",
|
||||
true
|
||||
)
|
||||
}
|
||||
|
||||
override val showQuiltOption: Boolean by lazy { ConfigManager.getConfigItem("loaders.quilt.enabled", false) }
|
||||
|
||||
override fun setLoaderType(loader: LoaderType?) {
|
||||
selectedLoaderType.value = loader
|
||||
}
|
||||
|
||||
override fun setLoaderVersion(loaderVersion: String) {
|
||||
scope.launch {
|
||||
loaderVersions.first().let { versions ->
|
||||
if (versions != null) {
|
||||
for (version in versions) {
|
||||
if (version.version == loaderVersion) {
|
||||
selectedLoaderVersion.value = version
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val fabricDisabledMCVersions: List<String> by lazy {
|
||||
ConfigManager.getConfigItem(
|
||||
"loaders.fabric.disabledMinecraftVersions", emptyList()
|
||||
)
|
||||
}
|
||||
|
||||
private val legacyFabricDisabledMCVersions: List<String> by lazy {
|
||||
ConfigManager.getConfigItem(
|
||||
"loaders.fabric.disabledMinecraftVersions", emptyList()
|
||||
)
|
||||
}
|
||||
|
||||
private val forgeDisabledMCVersions: List<String> by lazy {
|
||||
ConfigManager.getConfigItem(
|
||||
"loaders.forge.disabledMinecraftVersions", emptyList()
|
||||
)
|
||||
}
|
||||
|
||||
private val quiltDisabledMCVersions: List<String> by lazy {
|
||||
ConfigManager.getConfigItem(
|
||||
"loaders.quilt.disabledMinecraftVersions", emptyList()
|
||||
)
|
||||
}
|
||||
|
||||
override fun createServer() {
|
||||
install(true)
|
||||
}
|
||||
|
||||
override fun createInstance() {
|
||||
install(false)
|
||||
}
|
||||
|
||||
override fun onSettingsSaved() {
|
||||
font.value = (App.THEME.boldFont)
|
||||
}
|
||||
|
||||
override val warnUserAboutServer: Boolean
|
||||
get() {
|
||||
return InstanceManager.getInstances().size == 0
|
||||
}
|
||||
|
||||
init {
|
||||
SettingsManager.addListener(this)
|
||||
scope.launch {
|
||||
selectedMinecraftVersionFlow.collect { selectedVersion ->
|
||||
if (selectedVersion != null) {
|
||||
try {
|
||||
val version = MinecraftManager.getMinecraftVersion(selectedVersion)
|
||||
createServerEnabled.value = version.hasServer()
|
||||
} catch (ignored: InvalidMinecraftVersion) {
|
||||
createServerEnabled.value = false
|
||||
}
|
||||
} else {
|
||||
createServerEnabled.value = false
|
||||
}
|
||||
|
||||
val defaultNameFieldValue = String.format(
|
||||
"Minecraft %s", selectedVersion
|
||||
)
|
||||
if (name.value == null || name.value!!.isEmpty() || !nameDirty) {
|
||||
nameDirty = false
|
||||
name.value = (defaultNameFieldValue)
|
||||
}
|
||||
if (description.value == null || description.value!!.isEmpty() || !descriptionDirty) {
|
||||
descriptionDirty = false
|
||||
description.value = (defaultNameFieldValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scope.launch {
|
||||
selectedLoaderType.combine(selectedMinecraftVersionFlow) { a, b ->
|
||||
a to b
|
||||
}.collect { (loaderType, selectedMinecraftVersion) ->
|
||||
if (selectedMinecraftVersion == null) return@collect
|
||||
loaderVersionsDropDownEnabled.value = false
|
||||
if (loaderType == null) {
|
||||
// update the name and description fields if they're not dirty
|
||||
val defaultNameFieldValue = String.format("Minecraft %s", selectedMinecraftVersion)
|
||||
if (!nameDirty) {
|
||||
name.value = defaultNameFieldValue
|
||||
}
|
||||
if (!descriptionDirty) {
|
||||
description.value = defaultNameFieldValue
|
||||
}
|
||||
loaderVersions.value = arrayOf(LoaderVersion(GetText.tr("Select Loader First")))
|
||||
return@collect
|
||||
}
|
||||
loaderLoading.value = true
|
||||
|
||||
setLoaderGroupEnabled(false)
|
||||
|
||||
// Legacy Forge doesn't support servers easily
|
||||
val enableCreateServers = (loaderType !== LoaderType.FORGE || !Utils.matchVersion(
|
||||
selectedMinecraftVersion, "1.5", true, true
|
||||
))
|
||||
val loaders = if (ConfigManager.getConfigItem("useGraphql.vanillaLoaderVersions", false) == true) {
|
||||
apolloLoad(loaderType, selectedMinecraftVersion, enableCreateServers)
|
||||
} else {
|
||||
legacyLoad(loaderType, selectedMinecraftVersion, enableCreateServers)
|
||||
}
|
||||
|
||||
loaderVersions.value = loaders
|
||||
|
||||
if (loaders.isNotEmpty()) {
|
||||
selectedLoaderVersion.value =
|
||||
when (loaderType) {
|
||||
LoaderType.FORGE -> {
|
||||
loaders.firstOrNull { it.recommended } ?: loaders.first()
|
||||
}
|
||||
else -> {
|
||||
loaders.first()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
setLoaderGroupEnabled(true, enableCreateServers)
|
||||
|
||||
updateNameAndDescription(selectedMinecraftVersion, loaderType)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun apolloLoad(
|
||||
selectedLoader: LoaderType, selectedMinecraftVersion: String?, enableCreateServers: Boolean
|
||||
): Array<LoaderVersion> {
|
||||
try {
|
||||
val response = GraphqlClient.apolloClient.query(
|
||||
GetLoaderVersionsForMinecraftVersionQuery(
|
||||
selectedMinecraftVersion!!
|
||||
)
|
||||
).toBuilder().httpCachePolicy(
|
||||
HttpCachePolicy.Policy(
|
||||
HttpCachePolicy.FetchStrategy.CACHE_FIRST, 5, TimeUnit.MINUTES, false
|
||||
)
|
||||
).build().await()
|
||||
|
||||
val loaderVersionsList: MutableList<LoaderVersion> = ArrayList()
|
||||
when (selectedLoader) {
|
||||
LoaderType.FABRIC -> {
|
||||
loaderVersionsList.addAll(response.data!!.loaderVersions().fabric().stream()
|
||||
.filter { fv: GetLoaderVersionsForMinecraftVersionQuery.Fabric ->
|
||||
!disabledFabricVersions.contains(fv.version())
|
||||
}.map { version: GetLoaderVersionsForMinecraftVersionQuery.Fabric ->
|
||||
LoaderVersion(version.version(), false, "Fabric")
|
||||
}.collect(Collectors.toList())
|
||||
)
|
||||
}
|
||||
|
||||
LoaderType.FORGE -> {
|
||||
loaderVersionsList.addAll(response.data!!.loaderVersions().forge().stream()
|
||||
.filter { fv: GetLoaderVersionsForMinecraftVersionQuery.Forge ->
|
||||
!disabledForgeVersions.contains(fv.version())
|
||||
}.map { version: GetLoaderVersionsForMinecraftVersionQuery.Forge ->
|
||||
val lv = LoaderVersion(
|
||||
version.version(), version.rawVersion(), version.recommended(), "Forge"
|
||||
)
|
||||
if (version.installerSha1Hash() != null && version.installerSize() != null) {
|
||||
lv.downloadables["installer"] = Pair(
|
||||
version.installerSha1Hash(), version.installerSize()!!.toLong()
|
||||
)
|
||||
}
|
||||
if (version.universalSha1Hash() != null && version.universalSize() != null) {
|
||||
lv.downloadables["universal"] = Pair(
|
||||
version.universalSha1Hash(), version.universalSize()!!.toLong()
|
||||
)
|
||||
}
|
||||
if (version.clientSha1Hash() != null && version.clientSize() != null) {
|
||||
lv.downloadables["client"] = Pair(
|
||||
version.clientSha1Hash(), version.clientSize()!!.toLong()
|
||||
)
|
||||
}
|
||||
if (version.serverSha1Hash() != null && version.serverSize() != null) {
|
||||
lv.downloadables["server"] = Pair(
|
||||
version.serverSha1Hash(), version.serverSize()!!.toLong()
|
||||
)
|
||||
}
|
||||
lv
|
||||
}.collect(Collectors.toList())
|
||||
)
|
||||
}
|
||||
|
||||
LoaderType.QUILT -> {
|
||||
loaderVersionsList.addAll(response.data!!.loaderVersions().quilt().stream()
|
||||
.filter { fv: GetLoaderVersionsForMinecraftVersionQuery.Quilt ->
|
||||
!disabledQuiltVersions.contains(fv.version())
|
||||
}.map { version: GetLoaderVersionsForMinecraftVersionQuery.Quilt ->
|
||||
LoaderVersion(version.version(), false, "Quilt")
|
||||
}.collect(Collectors.toList())
|
||||
)
|
||||
}
|
||||
|
||||
LoaderType.LEGACY_FABRIC -> {
|
||||
|
||||
loaderVersionsList.addAll(response.data!!.loaderVersions().legacyfabric()
|
||||
.stream()
|
||||
.filter { fv -> !disabledLegacyFabricVersions.contains(fv.version()) }
|
||||
.map { version ->
|
||||
LoaderVersion(
|
||||
version.version(),
|
||||
false,
|
||||
"LegacyFabric"
|
||||
)
|
||||
}
|
||||
.collect(Collectors.toList())
|
||||
)
|
||||
}
|
||||
}
|
||||
if (loaderVersionsList.size == 0) {
|
||||
setLoaderGroupEnabled(true, enableCreateServers)
|
||||
return arrayOf(noLoaderVersions)
|
||||
}
|
||||
return loaderVersionsList.toTypedArray()
|
||||
} catch (e: ApolloException) {
|
||||
LogManager.logStackTrace("Error fetching loading versions", e)
|
||||
setLoaderGroupEnabled(true, enableCreateServers)
|
||||
return arrayOf(errorLoadingVersions)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setLoaderGroupEnabled(enabled: Boolean, enableCreateServers: Boolean = enabled) {
|
||||
loaderTypeNoneEnabled.value = enabled
|
||||
loaderTypeFabricEnabled.value = enabled
|
||||
loaderTypeForgeEnabled.value = enabled
|
||||
loaderTypeLegacyFabricEnabled.value = enabled
|
||||
loaderTypeQuiltEnabled.value = enabled
|
||||
createServerEnabled.value = enableCreateServers
|
||||
createInstanceEnabled.value = enabled
|
||||
loaderVersionsDropDownEnabled.value = enabled
|
||||
}
|
||||
|
||||
private val disabledQuiltVersions: List<String> by lazy {
|
||||
ConfigManager.getConfigItem(
|
||||
"loaders.quilt.disabledVersions", emptyList()
|
||||
)
|
||||
}
|
||||
|
||||
private val disabledFabricVersions: List<String> by lazy {
|
||||
ConfigManager.getConfigItem(
|
||||
"loaders.fabric.disabledVersions", emptyList()
|
||||
)
|
||||
}
|
||||
|
||||
private val disabledLegacyFabricVersions: List<String> by lazy {
|
||||
ConfigManager.getConfigItem(
|
||||
"loaders.legacyfabric.disabledVersions", emptyList()
|
||||
)
|
||||
}
|
||||
|
||||
private val disabledForgeVersions: List<String> by lazy {
|
||||
ConfigManager.getConfigItem(
|
||||
"loaders.forge.disabledVersions", emptyList()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Use legacy loading mechanic
|
||||
*/
|
||||
fun legacyLoad(
|
||||
selectedLoader: LoaderType, selectedMinecraftVersion: String, enableCreateServers: Boolean
|
||||
): Array<LoaderVersion> {
|
||||
val loaderVersionsList: MutableList<LoaderVersion> = ArrayList()
|
||||
loaderVersionsList.addAll(
|
||||
when (selectedLoader) {
|
||||
LoaderType.FABRIC -> FabricLoader.getChoosableVersions(selectedMinecraftVersion)
|
||||
LoaderType.FORGE -> ForgeLoader.getChoosableVersions(selectedMinecraftVersion)
|
||||
LoaderType.QUILT -> QuiltLoader.getChoosableVersions(selectedMinecraftVersion)
|
||||
LoaderType.LEGACY_FABRIC -> LegacyFabricLoader.getChoosableVersions(selectedMinecraftVersion)
|
||||
}
|
||||
)
|
||||
if (loaderVersionsList.size == 0) {
|
||||
setLoaderGroupEnabled(true, enableCreateServers)
|
||||
return arrayOf(noLoaderVersions)
|
||||
}
|
||||
|
||||
return loaderVersionsList.toTypedArray()
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the name and description fields if they're not dirty with loader type information
|
||||
*/
|
||||
private fun updateNameAndDescription(
|
||||
selectedMinecraftVersion: String, selectedLoader: LoaderType
|
||||
) {
|
||||
val defaultNameFieldValue = String.format(
|
||||
"Minecraft %s with %s", selectedMinecraftVersion, selectedLoader.toString()
|
||||
)
|
||||
if (!nameDirty) {
|
||||
name.value = defaultNameFieldValue
|
||||
}
|
||||
if (!descriptionDirty) {
|
||||
description.value = defaultNameFieldValue
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val noLoaderVersions = LoaderVersion(GetText.tr("No Versions Found"))
|
||||
private val errorLoadingVersions = LoaderVersion(GetText.tr("Error Getting Versions"))
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue