diff --git a/.idea/artifacts/TAL_jar.xml b/.idea/artifacts/TAL_jar.xml
new file mode 100644
index 0000000..3e03979
--- /dev/null
+++ b/.idea/artifacts/TAL_jar.xml
@@ -0,0 +1,10 @@
+
+
+ $PROJECT_DIR$/out/artifacts/TAL_jar
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/libRefTools.xml b/.idea/libraries/libRefTools.xml
index c38d72c..2ce2aba 100644
--- a/.idea/libraries/libRefTools.xml
+++ b/.idea/libraries/libRefTools.xml
@@ -4,8 +4,6 @@
-
-
-
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 2404a4c..59225cf 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -9,4 +9,5 @@
+
\ No newline at end of file
diff --git a/TAL.iml b/TAL.iml
index f0db93c..f6ccf03 100644
--- a/TAL.iml
+++ b/TAL.iml
@@ -7,7 +7,6 @@
-
@@ -17,5 +16,6 @@
+
\ No newline at end of file
diff --git a/libs/libRefTools.jar b/libs/libRefTools.jar
index 9fb9834..02b5c30 100644
Binary files a/libs/libRefTools.jar and b/libs/libRefTools.jar differ
diff --git a/src/Launcher/Main.java b/src/Launcher/Main.java
index 86ff329..de7f54f 100644
--- a/src/Launcher/Main.java
+++ b/src/Launcher/Main.java
@@ -10,48 +10,71 @@ favour and pour yourself some nice Jack Daniels. You deserve it if you're going
package Launcher;
+import Launcher.net.Updater;
import com.tofvesson.reflection.SafeReflection;
+import javafx.animation.KeyFrame;
+import javafx.animation.Timeline;
import javafx.application.Application;
-import javafx.fxml.FXMLLoader;
+import javafx.scene.Node;
import javafx.scene.Scene;
-import javafx.scene.control.Button;
-import javafx.scene.control.Tab;
-import javafx.scene.control.TextField;
+import javafx.scene.control.*;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Pane;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
-import java.net.URL;
+import java.io.File;
import com.tofvesson.async.*;
+import javafx.util.Duration;
public class Main extends Application {
- public static final URL mainLauncher = Main.class.getResource("../assets/layout/main.fxml"); // Launcher body
+ // Semantic versioning system data
+ public static final String semVerDevState = "PreDev"; // Development stage
+ public static final int semVerMajor = 0; // Major version
+ public static final int semVerMinor = 2; // Minor version
+ public static final int semVerPatch = 2; // Patch version
private double xOffset = 0, yOffset = 0; // Offsets for dragging
- private Button exit, min, Home_btn, Modpack_btn, Settings_btn, Instance_btn; // Define buttons
+ private static String[] args;
+ private Button exit, min, Home_btn, Modpack_btn, Settings_btn, Instance_btn; // Define buttons
private ImageView icon;
private TextField Search_modpacks;
private Image appIcon;
private Rectangle dragBar; // Draggable top bar
private Pane root, tab;
- private Tabs activeTab = Tabs.Home;
+ private Node activeTab, settings_activeTab;
Async stringUpdater;
@Override
public void start(Stage primaryStage) throws Exception{
- primaryStage.initStyle(StageStyle.UNDECORATED); // Remove ugly trash
+ primaryStage.initStyle(StageStyle.UNDECORATED);
- root = FXMLLoader.load(mainLauncher);
+ if(args.length<2 || !args[1].equals("false")){
+ Stage d = new Stage();
+ Timeline t = new Timeline();
+ t.getKeyFrames().add(new KeyFrame(Duration.millis(1), event ->{ d.close(); primaryStage.show(); }));
+ d.initStyle(StageStyle.UNDECORATED);
+ Pane n = (Pane) Tabs.load("dialog_update");
+ d.setScene(new Scene(n));
+ d.show();
+ Thread t1 = new Thread(()->{
+ try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); }
+ Updater.getInstance(t);
+ });
+ t1.setDaemon(true);
+ t1.start();
+ } else primaryStage.show(); // Remove ugly trash
+
+ root = (Pane) Tabs.load("main"); // Load via layout loader
+ ((Label)root.lookup("#version")).setText(((Label) root.lookup("#version")) // Dynamically set version label
+ .getText().replace("$v", semVerDevState+"-"+semVerMajor+"."+semVerMinor+"."+semVerPatch)); // Use variables to define version
primaryStage.setTitle("Team-Avion Launcher [WIP]");
primaryStage.setScene(new Scene(root, 900, 500));
- primaryStage.show();
primaryStage.getIcons().clear();
- primaryStage.getIcons().add(appIcon = new Image(getClass().getResourceAsStream("../assets/icons/app.png")));
-
+ primaryStage.getIcons().add(appIcon = new Image(getClass().getResourceAsStream("/assets/icons/app.png")));
// Field initialization
exit = (Button) root.lookup("#exit");
@@ -70,45 +93,66 @@ public class Main extends Application {
Search_modpacks = (TextField) root.lookup("#search-modpacks");
-
// Infrastructural navigation
exit.setOnMouseClicked(event -> primaryStage.close()); // Closes the program if exit button is clicked
min.setOnMouseClicked(event -> primaryStage.setIconified(true)); // Minimizes the program if minimize button is clicked
Home_btn.setOnMouseClicked(event ->{
- if(activeTab!=Tabs.Home){
- (activeTab=Tabs.Home).switchTab(tab);
+ if(!activeTab.equals(Home_btn)){
+ updateTabSelection(Home_btn, TabType.MAIN);
+ Tabs.switchTab("home", tab);
}
}); // Sets the active tab to the home tab unless it's already active
Modpack_btn.setOnMouseClicked(event ->{
- if(activeTab!=Tabs.Modpacks){
+ if(!activeTab.equals(Modpack_btn)){
+ updateTabSelection(Modpack_btn, TabType.MAIN);
+ Tabs.switchTab("modpacks", tab);
if(stringUpdater!=null && stringUpdater.isAlive()) stringUpdater.cancel();
- (activeTab=Tabs.Modpacks).switchTab(tab); // Sets the active tab to the modpacks tab unless it's already active
-
- //TODO: Create a dynamic updating string from the input ( Text Field ) *-* Done *-*
-
-
- stringUpdater = new Async(SafeReflection.getFirstMethod(Main.class, "detectStringUpdate"), Tabs.Modpacks.loaded.lookup("#search-modpacks"));
-
+ stringUpdater = new Async(SafeReflection.getFirstMethod(Main.class, "detectStringUpdate"), Tabs.load("modpacks").lookup("#search-modpacks"));
}
});
Instance_btn.setOnMouseClicked(event -> {
- if(activeTab!=Tabs.Instance){
- (activeTab = Tabs.Instance).switchTab(tab);
+ if(!activeTab.equals(Instance_btn)){
+ updateTabSelection(Instance_btn, TabType.MAIN);
+ Tabs.switchTab("instance", tab);
+ Tabs.load("instance").lookup("#Launch-VM").setOnMouseClicked(event1 -> {
+ });
}
});
Settings_btn.setOnMouseClicked(event ->{
- if(activeTab!=Tabs.Settings){
- (activeTab=Tabs.Settings).switchTab(tab); // Sets the active tab to the settings tab unless it's already active
+ if(!activeTab.equals(Settings_btn)){
+ updateTabSelection(Settings_btn, TabType.MAIN);
+ Node n = Tabs.switchTab("settings", tab); // Sets the active tab to the settings tab unless it's already active
+ if(settings_activeTab==null) settings_activeTab = n.lookup("#Settings-Gen-btn"); // First time stuff
+
+ n.lookup("#Settings-Gen-btn").setOnMouseClicked(event1 -> {
+ // Generic Settings Sub-tab
+ if(!settings_activeTab.getId().equals(n.lookup("#Settings-Gen-btn").getId())){ // Use id to identify layouts
+ updateTabSelection(n.lookup("#Settings-Gen-btn"), TabType.SETTINGS);
+ Node genericLayout = Tabs.switchTab("settings_generic", (Pane) n.lookup("#Settings-Pane"));
+
+
+ }
+ });
+
+ n.lookup("#Settings-Mine-btn").setOnMouseClicked(event1 -> {
+ // Minecraft Settings Sub-tab
+ if(!settings_activeTab.getId().equals(n.lookup("#Settings-Mine-btn").getId())){ // Use id to identify layouts
+ updateTabSelection(n.lookup("#Settings-Mine-btn"), TabType.SETTINGS);
+ Node minecraftLayout = Tabs.switchTab("settings_minecraft", (Pane) n.lookup("#Settings-Pane"));
+
+ }
+ });
+
+ Tabs.switchTab(settings_activeTab.getId().equals("Settings-Gen-btn") ? "settings_generic" : "settings_minecraft", (Pane) n.lookup("#Settings-Pane"));
}
});
-
// Drag
dragBar.setOnMousePressed(event -> {
xOffset = event.getSceneX();
@@ -119,20 +163,42 @@ public class Main extends Application {
primaryStage.setY(event.getScreenY() - yOffset);
});
-
// Set up default layout
- Tabs.Home.switchTab(tab);
+ activeTab = Home_btn; // Update selected tab
+ Tabs.switchTab("home", tab);
icon.setImage(appIcon);
}
- public static void main(String[] args) {
+ public static void main(String[] args) throws Exception{
+ Main.args = args;
+ if (args.length > 0) {
+ File f = new File(args[0]);
+ if (f.isFile()) f.delete(); // Delete previous jar
+ }
launch(args);
}
+ /**
+ * Search for packs with an 80% match compared to detected string.
+ * @param toRead TextField to read from.
+ */
public static void detectStringUpdate(TextField toRead){
String s = "";
while(true) if(!s.equals(toRead.getText())) System.out.println(s = toRead.getText());
}
+ void updateTabSelection(Node newTab, TabType t){
+ Node n = t==TabType.MAIN?activeTab:settings_activeTab;
+ n.getStyleClass().remove("selected");
+ n.getStyleClass().add("tab");
+ if(t==TabType.MAIN) activeTab = newTab;
+ else settings_activeTab = newTab;
+ newTab.getStyleClass().remove("tab");
+ newTab.getStyleClass().add("selected");
+ }
+
+ enum TabType{
+ SETTINGS, MAIN
+ }
}
diff --git a/src/Launcher/Tabs.java b/src/Launcher/Tabs.java
index d82baba..45b90ee 100644
--- a/src/Launcher/Tabs.java
+++ b/src/Launcher/Tabs.java
@@ -1,37 +1,73 @@
package Launcher;
+import com.tofvesson.collections.ShiftingList;
import javafx.fxml.FXMLLoader;
-import javafx.scene.Parent;
+import javafx.scene.Node;
import javafx.scene.layout.Pane;
+import javafx.util.Pair;
import java.io.IOException;
import java.net.URL;
-public enum Tabs {
+@SuppressWarnings("unused")
+public class Tabs {
- Modpacks(Tabs.class.getResource("../assets/layout/modpacks.fxml")),
- Home(Tabs.class.getResource("../assets/layout/home.fxml")),
- Settings(Tabs.class.getResource("../assets/layout/settings.fxml")),
- Instance(Tabs.class.getResource("../assets/layout/instance.fxml"));
+ private static final ShiftingList> loaded = new ShiftingList<>(35); // Memory-efficient list of loaded files
/**
- * Url referencing xml.
+ * Loads layout from file in layout assets folder. If layout is already loaded,
+ * Tabs won't bother with reloading and will instead return the cached version.
+ * @param fileName Name of fxml file to load. (Must be located in /assets/layout/ folder or name must define name subfolder in layouts folder)
+ * @return Generified object referring to loaded resource.
*/
- public final URL url;
-
- /**
- * Loaded layout
- */
- public final Parent loaded;
-
- Tabs(URL url){
- this.url = url;
- Parent p = null;
- try { p = FXMLLoader.load(url); } catch (IOException e) { e.printStackTrace(); }
- loaded = p;
+ public static Node load(String fileName){
+ if(!fileName.endsWith(".fxml")) fileName+=".fxml";
+ URL file = Main.class.getResource("/assets/layout/"+fileName);
+ try {
+ final boolean[] b = {false};
+ loaded.stream().filter(p -> p.getKey().equals(file)).forEach(p->b[0]=true);
+ if(!b[0]) loaded.add(new Pair<>(file, FXMLLoader.load(file))); // Load file if it isn't already loaded
+ final Node[] p1 = new Node[]{new Pane()};
+ loaded.stream().filter(p->p.getKey().equals(file)).forEach(p->p1[0]=p.getValue());
+ return p1[0];
+ } catch (IOException e) {
+ e.printStackTrace();
+ return new Pane(); // Returns empty layout if all else fails
+ }
}
- public void switchTab(Pane holder){
- holder.getChildren().clear();
- holder.getChildren().add(loaded);
+ /**
+ * Switches the currently loaded tab in holder pane. Removes current children from holder and adds new tab instead.
+ * If holder already contains layout, method simply returns the loaded resource.
+ * @param newTabName Name of file containing the new tab data.
+ * @param holder Pane where tab should be loaded to.
+ * @return Generified object referring to loaded resource.
+ */
+ public static Node switchTab(String newTabName, Pane holder){
+ Node n = load(newTabName);
+ if(!holder.getChildren().contains(n)) {
+ holder.getChildren().clear();
+ holder.getChildren().add(n);
+ }
+ return n;
+ }
+
+ /**
+ * Forces unloading of resource to free up resources and/or clear data.
+ * @param fileName Name of resource to unload.
+ */
+ public static void unloadTab(String fileName){
+ if(!fileName.endsWith(".fxml")) fileName+=".fxml";
+ URL file = Main.class.getResource("/assets/layout/"+fileName);
+ loaded.stream().filter(p->p.getKey().equals(file)).forEach(loaded::remove);
+ }
+
+ /**
+ * Forces unloading and the subsequent loading of a layout resource.
+ * @param fileName Name of resource to reload.
+ * @return Newly loaded layout.
+ */
+ public static Node reloadTab(String fileName){
+ unloadTab(fileName);
+ return load(fileName);
}
}
diff --git a/src/Launcher/minecraft/Launcher.java b/src/Launcher/minecraft/Launcher.java
new file mode 100644
index 0000000..9e31fcb
--- /dev/null
+++ b/src/Launcher/minecraft/Launcher.java
@@ -0,0 +1,5 @@
+package Launcher.minecraft;
+
+public class Launcher {
+
+}
diff --git a/src/Launcher/net/Updater.java b/src/Launcher/net/Updater.java
index 0b8d339..07a0b37 100644
--- a/src/Launcher/net/Updater.java
+++ b/src/Launcher/net/Updater.java
@@ -1,35 +1,111 @@
package Launcher.net;
-import java.io.IOException;
+import Launcher.Main;
+import com.tofvesson.async.Async;
+import com.tofvesson.reflection.SafeReflection;
+import javafx.animation.Timeline;
+import javax.net.ssl.HttpsURLConnection;
+import java.io.*;
+import java.net.MalformedURLException;
import java.net.URL;
-import java.net.URLConnection;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import static Launcher.Main.semVerMajor;
+import static Launcher.Main.semVerMinor;
+import static Launcher.Main.semVerPatch;
/**
* Simple thing for updating launcher
*/
public class Updater {
- private static Updater instance;
- private URLConnection conn;
+ private static volatile Updater instance;
+ private static Async setup;
+ public static final Pattern version = Pattern.compile("(?s).*?(\\d)\\.(\\d)\\.(\\d).*?"); // Pattern to match when finding refs
+ private HttpsURLConnection conn;
+ public static final URL updateURL;
- private Updater(String URL) throws IOException {
- conn = new URL(URL).openConnection();
+ static {
+ URL u = null;
+ try { u = new URL("https://github.com/GabrielTofvesson/TeamAvionLauncher/releases"); } catch (MalformedURLException e) { e.printStackTrace(); }
+ updateURL = u;
}
- public void downloadStuff(){
- //TODO: Download lots of stuff
- }
+ private Updater(Timeline t){
+ try {
+ conn = (HttpsURLConnection) updateURL.openConnection();
+ conn.setDoOutput(true);
+ conn.setDoInput(true);
+ conn.setRequestMethod("GET");
+ conn.setRequestProperty("User-Agent", "Mozilla/5.0");
+ if(conn.getResponseCode()!=200){
+ t.play();
+ return; // Can't get update site
+ }
+ conn.connect();
- public void downloadMoreStuff(){
- //TODO: Download more stuff
- }
- public void downloadEvenMoreStuff(){
- //TODO: Download even more stuff
- }
+ BufferedReader in = new BufferedReader(new InputStreamReader(
+ conn.getInputStream()));
+ String inputLine;
+ StringBuilder response = new StringBuilder();
+ while ((inputLine = in.readLine()) != null) response.append(inputLine);
+ in.close();
- public static Updater getInstance(String url) throws IOException {
- if(instance==null) instance = new Updater(url);
- return instance;
+ Matcher m = version.matcher(response.toString());
+ String downloadLink = "";
+ int semMajor = semVerMajor, semMinor = semVerMinor, semPatch = semVerPatch;
+ while(m.find()){
+ int semMaj = Integer.parseInt(m.group(1)),
+ semMin = Integer.parseInt(m.group(2)),
+ semPat = Integer.parseInt(m.group(3));
+ if(semMaj < semMajor || (semMaj==semMajor && semMin(SafeReflection.getFirstConstructor(Updater.class), t); }
+
+ public static Updater getInstance(Timeline t) {
+ if(setup==null) checkUpdate(t);
+ return instance==null?instance=setup.await():instance; // Await async creation
}
}
diff --git a/src/META-INF/MANIFEST.MF b/src/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..33021cc
--- /dev/null
+++ b/src/META-INF/MANIFEST.MF
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Main-Class: Launcher.Main
+
diff --git a/src/assets/layout/dialog_update.fxml b/src/assets/layout/dialog_update.fxml
new file mode 100644
index 0000000..79fe1e9
--- /dev/null
+++ b/src/assets/layout/dialog_update.fxml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/assets/layout/home.fxml b/src/assets/layout/home.fxml
index b896070..2dbf270 100644
--- a/src/assets/layout/home.fxml
+++ b/src/assets/layout/home.fxml
@@ -5,15 +5,13 @@
-
-
+
-
-
-
diff --git a/src/assets/layout/instance.fxml b/src/assets/layout/instance.fxml
index b37f150..34ccae5 100644
--- a/src/assets/layout/instance.fxml
+++ b/src/assets/layout/instance.fxml
@@ -1,18 +1,24 @@
+
-
-
+
-
-
+
+
+
+
+
+
+
+
-
\ No newline at end of file
+
diff --git a/src/assets/layout/instance_userinfo.fxml b/src/assets/layout/instance_userinfo.fxml
new file mode 100644
index 0000000..2e3a367
--- /dev/null
+++ b/src/assets/layout/instance_userinfo.fxml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/src/assets/layout/main.fxml b/src/assets/layout/main.fxml
index a725d1e..c3709b2 100644
--- a/src/assets/layout/main.fxml
+++ b/src/assets/layout/main.fxml
@@ -7,40 +7,40 @@
-
+
-
-
-
+
+
+
-
-