diff --git a/linux/generateRepo.sh b/linux/generateRepo.sh index f0a62e0..5da38d4 100644 --- a/linux/generateRepo.sh +++ b/linux/generateRepo.sh @@ -52,7 +52,8 @@ while IFS= read -r line; do dirfile=$(dirname "${line}") filename=$(basename "${line}") filenamezsync=$(basename "${zsyncfile}") - $(cd "${dirfile}" && zsyncmake -o "${filenamezsync}" "${filename}") + fileurl=$(python3 -c "import urllib.parse; print(urllib.parse.quote(input()))" <<< "${filename}") + $(cd "${dirfile}" && zsyncmake -u ${fileurl} -o "${filenamezsync}" "${filename}") if [ $? -eq 0 ]; then echo "Success: Generated ${zsyncfile}" else diff --git a/src/main/java/de/mc8051/arma3launcher/LauncherGUI.form b/src/main/java/de/mc8051/arma3launcher/LauncherGUI.form index d7f9864..3c015de 100644 --- a/src/main/java/de/mc8051/arma3launcher/LauncherGUI.form +++ b/src/main/java/de/mc8051/arma3launcher/LauncherGUI.form @@ -701,38 +701,60 @@ - - + + + + + + + + + + + - + + + - + + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + @@ -2049,7 +2071,7 @@ - + diff --git a/src/main/java/de/mc8051/arma3launcher/LauncherGUI.java b/src/main/java/de/mc8051/arma3launcher/LauncherGUI.java index a14b39a..fb8d11c 100644 --- a/src/main/java/de/mc8051/arma3launcher/LauncherGUI.java +++ b/src/main/java/de/mc8051/arma3launcher/LauncherGUI.java @@ -20,6 +20,8 @@ import de.mc8051.arma3launcher.repo.FileChecker; import de.mc8051.arma3launcher.repo.RepositoryManger; import de.mc8051.arma3launcher.repo.SyncList; import de.mc8051.arma3launcher.repo.Syncer; +import de.mc8051.arma3launcher.repo.Updater; +import de.mc8051.arma3launcher.repo.Version; import de.mc8051.arma3launcher.steam.SteamTimer; import de.mc8051.arma3launcher.utils.Callback; import de.mc8051.arma3launcher.utils.Humanize; @@ -132,7 +134,6 @@ public class LauncherGUI implements Observer { private JButton syncCheckAbortButton; private JButton syncIntensiveCheckButton; public JProgressBar syncDownloadProgress; - public JProgressBar syncFileProgress; private JButton syncDownloadButton; private JButton syncDownloadAbortButton; private JButton syncPauseButton; @@ -171,11 +172,13 @@ public class LauncherGUI implements Observer { private JTextPane presetNoteTextPane; private JPanel presetNotePaneWrapper; private JPanel presetNotePane; + private JLabel aboutUpdateLabel; private JCheckBoxTree repoTree; private FileChecker fileChecker; private Syncer syncer; private SyncList lastSynclist = null; + private Updater updater = new Updater(); public LauncherGUI() { fileChecker = new FileChecker(syncCheckProgress); @@ -473,7 +476,7 @@ public class LauncherGUI implements Observer { Object newNameO = JOptionPane.showInputDialog(null, "", LangUtils.getInstance().getString("new_modset_name"), JOptionPane.QUESTION_MESSAGE, null, null, selectedModset.getName()); - if(newNameO == null) return; + if (newNameO == null) return; String newName = (String) newNameO; if (newName.isEmpty()) return; if (Modset.MODSET_LIST.containsKey(newName)) { @@ -494,7 +497,7 @@ public class LauncherGUI implements Observer { DefaultComboBoxModel model = (DefaultComboBoxModel) syncPresetCombo.getModel(); Modset elementAt = model.getElementAt(((JComboBox) e.getItemSelectable()).getSelectedIndex()); repoTree.setCheckboxesChecked(false); - if(elementAt.getType() == Modset.Type.PLACEHOLDER) return; + if (elementAt.getType() == Modset.Type.PLACEHOLDER) return; List collect = elementAt.getMods().stream().map(Mod::getName).collect(Collectors.toList()); @@ -503,7 +506,7 @@ public class LauncherGUI implements Observer { for (int i = 0; i < root.getChildCount(); i++) { TreeNode childAt = root.getChildAt(i); - if(!collect.contains(childAt.toString())) continue; + if (!collect.contains(childAt.toString())) continue; final TreePath treePath = new TreePath(new TreeNode[]{root, childAt}); repoTree.checkSubTree(treePath, true); repoTree.updatePredecessorsWithCheckMode(treePath, true); @@ -514,6 +517,12 @@ public class LauncherGUI implements Observer { } } }); + + updater.needUpdate((needUpdate, newestVersion) -> { + if (needUpdate) { + SwingUtilities.invokeLater(() -> warnBox(LangUtils.getInstance().getString("client_outdated"), LangUtils.getInstance().getString("please_update"))); + } + }); } public static void infoBox(String infoMessage, String titleBar) { @@ -1104,7 +1113,6 @@ public class LauncherGUI implements Observer { syncPauseButton.setEnabled(false); syncStatusLabel.setText("Sync stopped"); - syncFileProgress.setValue(0); TaskBarUtils.getInstance().setValue(0); TaskBarUtils.getInstance().off(); }); @@ -1116,8 +1124,6 @@ public class LauncherGUI implements Observer { syncPauseButton.setEnabled(false); syncStatusLabel.setText("Sync finished"); - syncFileProgress.setValue(0); - syncFileProgress.setString(""); TaskBarUtils.getInstance().setValue(0); TaskBarUtils.getInstance().off(); TaskBarUtils.getInstance().attention(); @@ -1137,7 +1143,6 @@ public class LauncherGUI implements Observer { syncPauseButton.setEnabled(true); syncPauseButton.setText(LangUtils.getInstance().getString("resume")); syncDownloadButton.setEnabled(false); - syncFileProgress.setValue(0); TaskBarUtils.getInstance().paused(); }); } @@ -1145,7 +1150,7 @@ public class LauncherGUI implements Observer { private void updateModsetList() { SwingUtilities.invokeLater(() -> { - if (((DefaultComboBoxModel)syncPresetCombo.getModel()).getSize() > 0){ + if (((DefaultComboBoxModel) syncPresetCombo.getModel()).getSize() > 0) { syncPresetCombo.setSelectedIndex(0); } PresetTableModel model = (PresetTableModel) presetList.getModel(); @@ -1221,6 +1226,19 @@ public class LauncherGUI implements Observer { case SETTING: settingsPanelButton.setBackground(focusBackgroundColor); break; + + case ABOUT: + updater.needUpdate(new Callback.NeedUpdateCallback() { + @Override + public void response(boolean needUpdate, Version newestVersion) { + if (needUpdate) { + SwingUtilities.invokeLater(() -> aboutUpdateLabel.setText(LangUtils.getInstance().getString("client_outdated") + ": v" + newestVersion.get())); + } else { + SwingUtilities.invokeLater(() -> aboutUpdateLabel.setText(LangUtils.getInstance().getString("client_up_to_date"))); + } + } + }); + break; } tabbedPane1.setSelectedIndex(tab.getIndex()); diff --git a/src/main/java/de/mc8051/arma3launcher/repo/RepositoryManger.java b/src/main/java/de/mc8051/arma3launcher/repo/RepositoryManger.java index dffd8a4..82ef983 100644 --- a/src/main/java/de/mc8051/arma3launcher/repo/RepositoryManger.java +++ b/src/main/java/de/mc8051/arma3launcher/repo/RepositoryManger.java @@ -51,7 +51,7 @@ public class RepositoryManger implements Observable { statusMap.put(Type.CHANGELOG, DownloadStatus.FINNISHED); } - private void getAsync(String urlS, Callback.HttpCallback callback) { + public void getAsync(String urlS, Callback.HttpCallback callback) { new Thread(() -> { try { URI url = new URI(urlS); diff --git a/src/main/java/de/mc8051/arma3launcher/repo/SyncListener.java b/src/main/java/de/mc8051/arma3launcher/repo/SyncListener.java new file mode 100644 index 0000000..03a1ff2 --- /dev/null +++ b/src/main/java/de/mc8051/arma3launcher/repo/SyncListener.java @@ -0,0 +1,29 @@ +package de.mc8051.arma3launcher.repo; + +import co.bitshfted.xapps.zsync.Zsync; +import co.bitshfted.xapps.zsync.http.ContentRange; + +import java.net.URI; +import java.nio.file.Path; +import java.util.List; + +/** + * Created by gurkengewuerz.de on 29.03.2020. + */ +public interface SyncListener { + + public void bytesDownloaded(long bytes); + public void remoteFileDownloadingInitiated(List ranges); + public void remoteFileDownloadingStarted(long length); + public void remoteFileDownloadingComplete(); + public void controlFileDownloadingComplete(); + public void controlFileDownloadingStarted(Path path, long length); + public void controlFileReadingComplete(); + public void outputFileWritingStarted(long length); + public void outputFileWritingCompleted(); + public void inputFileReadingStarted(Path inputFile, long length); + public void inputFileReadingComplete(); + public void zsyncComplete(); + public void zsyncFailed(Exception exception); + public void zsyncStarted(Zsync.Options options); +} diff --git a/src/main/java/de/mc8051/arma3launcher/repo/SyncObserver.java b/src/main/java/de/mc8051/arma3launcher/repo/SyncObserver.java new file mode 100644 index 0000000..84d1648 --- /dev/null +++ b/src/main/java/de/mc8051/arma3launcher/repo/SyncObserver.java @@ -0,0 +1,107 @@ +package de.mc8051.arma3launcher.repo; + +import co.bitshfted.xapps.zsync.Zsync; +import co.bitshfted.xapps.zsync.ZsyncStatsObserver; +import co.bitshfted.xapps.zsync.http.ContentRange; + +import java.net.URI; +import java.nio.file.Path; +import java.util.List; + +/** + * Created by gurkengewuerz.de on 29.03.2020. + */ +public class SyncObserver extends ZsyncStatsObserver { + + private final SyncListener listener; + + public SyncObserver(SyncListener listener) { + super(); + this.listener = listener; + } + + @Override + public void zsyncStarted(URI requestedZsyncUri, Zsync.Options options) { + super.zsyncStarted(requestedZsyncUri, options); + listener.zsyncStarted(options); + } + + @Override + public void zsyncComplete() { + super.zsyncComplete(); + listener.zsyncComplete(); + } + + @Override + public void zsyncFailed(Exception exception) { + super.zsyncFailed(exception); + listener.zsyncFailed(exception); + } + + @Override + public void inputFileReadingStarted(Path inputFile, long length) { + super.inputFileReadingStarted(inputFile, length); + listener.inputFileReadingStarted(inputFile, length); + } + + @Override + public void inputFileReadingComplete() { + super.inputFileReadingComplete(); + listener.inputFileReadingComplete(); + } + + @Override + public void controlFileDownloadingComplete() { + super.controlFileDownloadingComplete(); + listener.controlFileDownloadingComplete(); + } + + @Override + public void controlFileReadingStarted(Path path, long length) { + super.controlFileReadingStarted(path, length); + listener.controlFileDownloadingStarted(path, length); + } + + @Override + public void controlFileReadingComplete() { + super.controlFileReadingComplete(); + listener.controlFileReadingComplete(); + } + + @Override + public void outputFileWritingStarted(Path outputFile, long length) { + super.outputFileWritingStarted(outputFile, length); + listener.outputFileWritingStarted(length); + } + + @Override + public void outputFileWritingCompleted() { + super.outputFileWritingCompleted(); + listener.outputFileWritingCompleted(); + } + + @Override + public void remoteFileDownloadingInitiated(URI uri, List ranges) { + super.remoteFileDownloadingInitiated(uri, ranges); + listener.remoteFileDownloadingInitiated(ranges); + } + + @Override + public void remoteFileDownloadingStarted(URI uri, long length) { + super.remoteFileDownloadingStarted(uri, length); + listener.remoteFileDownloadingStarted(length); + } + + @Override + public void remoteFileDownloadingComplete() { + super.remoteFileDownloadingComplete(); + listener.remoteFileDownloadingComplete(); + } + + @Override + public void bytesDownloaded(long bytes) { + super.bytesDownloaded(bytes); + listener.bytesDownloaded(bytes); + } + +} diff --git a/src/main/java/de/mc8051/arma3launcher/repo/Syncer.java b/src/main/java/de/mc8051/arma3launcher/repo/Syncer.java index cf91072..2513873 100644 --- a/src/main/java/de/mc8051/arma3launcher/repo/Syncer.java +++ b/src/main/java/de/mc8051/arma3launcher/repo/Syncer.java @@ -2,7 +2,8 @@ package de.mc8051.arma3launcher.repo; import co.bitshfted.xapps.zsync.Zsync; import co.bitshfted.xapps.zsync.ZsyncException; -import co.bitshfted.xapps.zsync.ZsyncObserver; +import co.bitshfted.xapps.zsync.ZsyncStatsObserver; +import co.bitshfted.xapps.zsync.http.ContentRange; import de.mc8051.arma3launcher.ArmA3Launcher; import de.mc8051.arma3launcher.LauncherGUI; import de.mc8051.arma3launcher.interfaces.Observable; @@ -16,6 +17,7 @@ import javax.swing.*; import java.io.IOException; import java.net.URI; import java.nio.file.Files; +import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; @@ -25,7 +27,7 @@ import java.util.logging.Logger; /** * Created by gurkengewuerz.de on 25.03.2020. */ -public class Syncer extends ZsyncObserver implements Observable { +public class Syncer implements Observable, SyncListener { private List observerList = new ArrayList<>(); @@ -37,19 +39,22 @@ public class Syncer extends ZsyncObserver implements Observable { private SyncList modlist; private boolean currentDownload_failed = false; - private String currentDownload_sizeS; - private boolean controlfile_downloaded = false; private int failed = 0; private int success = 0; private long syncSize; - private String syncSizeString; private int syncCount; - private long downloadStarted; - private long downloadEnded; - private long downloadSize; - private long downloadDownloaded; + private int syncRealCount; + + private SyncObserver syncObserver; + + private long speedCalcSize = 0L; + private long speedCalcTime = 0L; + + private long downloadDownloaded = 0L; + private long downloadStarted = 0L; + private long downloadSize = 0L; private Zsync zsync; private LauncherGUI gui; @@ -71,8 +76,12 @@ public class Syncer extends ZsyncObserver implements Observable { failed = 0; success = 0; + speedCalcSize = 0; + speedCalcTime = 0; + + syncRealCount = 0; + syncSize = ml.getSize(); - syncSizeString = Humanize.binaryPrefix(syncSize); syncCount = ml.getCount(); SwingUtilities.invokeLater(() -> { gui.syncDownloadProgress.setMaximum(syncCount); @@ -130,10 +139,9 @@ public class Syncer extends ZsyncObserver implements Observable { try { currentDownload = mf; currentDownload_failed = false; - controlfile_downloaded = false; - currentDownload_sizeS = Humanize.binaryPrefix(currentDownload.getSize()); - zsync.zsync(URI.create(mf.getRemoteFile() + ".zsync"), o, this); + syncObserver = new SyncObserver(this); + zsync.zsync(URI.create(mf.getRemoteFile() + ".zsync"), o, syncObserver); } catch (ZsyncException | IllegalArgumentException e) { Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, e); } @@ -183,42 +191,40 @@ public class Syncer extends ZsyncObserver implements Observable { } @Override - public void zsyncStarted(URI requestedZsyncUri, Zsync.Options options) { - super.zsyncStarted(requestedZsyncUri, options); - - SwingUtilities.invokeLater(() -> { - gui.syncFileProgress.setValue(0); - gui.syncFileProgress.setString("0 %"); - }); - - System.out.println("ZSync started " + options.getOutputFile()); + public void zsyncStarted(Zsync.Options options) { + Logger.getLogger(getClass().getName()).log(Level.INFO, "ZSync started " + options.getOutputFile()); SwingUtilities.invokeLater(() -> gui.syncStatusLabel.setText(currentDownload.getModPath() + ": Sync started")); } @Override public void zsyncFailed(Exception exception) { - super.zsyncFailed(exception); currentDownload_failed = true; - System.out.println("Zsync failed " + exception.getMessage()); + Logger.getLogger(getClass().getName()).log(Level.INFO, "Zsync failed " + exception.getMessage()); SwingUtilities.invokeLater(() -> gui.syncStatusLabel.setText(currentDownload.getModPath() + ": Sync failed")); } @Override public void zsyncComplete() { - super.zsyncComplete(); + speedCalcSize+=downloadDownloaded; + speedCalcTime+=System.currentTimeMillis()-downloadStarted; - downloadEnded = System.nanoTime(); - System.out.println(downloadSize); - System.out.println(downloadEnded - downloadStarted); - System.out.println((downloadSize / (downloadEnded - downloadStarted)) / 1000); + if (speedCalcSize > 20 * 1024 * 1024) { - System.out.println("Zsync complete"); + final double speedByte = ((double)speedCalcSize)/((double)speedCalcTime /1000); + SwingUtilities.invokeLater(() -> gui.syncDownloadSpeedLabel.setText(Humanize.binaryPrefix(Double.valueOf(speedByte).longValue()) + "/s")); + speedCalcSize = 0L; + speedCalcTime = 0L; + } + + Logger.getLogger(getClass().getName()).log(Level.INFO, "Zsync complete"); if (currentDownload_failed) failed++; else success++; - final long finalSize = syncSize - modlist.getSize(); + syncRealCount+=downloadDownloaded; + + final long finalSize = syncSize - ((syncSize - modlist.getSize() + currentDownload.getSize()) - syncRealCount); final int i = success + failed; final int percentage = (int) ((double) i / (double) Long.valueOf(syncCount).intValue() * 100); final String modPath = currentDownload.getModPath(); @@ -226,7 +232,7 @@ public class Syncer extends ZsyncObserver implements Observable { SwingUtilities.invokeLater(() -> { gui.syncDownloadProgress.setValue(i); gui.syncFileCountLabel.setText(i + "/" + syncCount + " (" + failed + " failed)"); - gui.syncSizeLabel.setText(Humanize.binaryPrefix(finalSize) + "/" + syncSizeString); + gui.syncSizeLabel.setText(Humanize.binaryPrefix(syncRealCount) + "/" + Humanize.binaryPrefix(finalSize)); if (currentDownload_failed) gui.syncStatusLabel.setText(modPath + ": Sync failed"); @@ -241,47 +247,65 @@ public class Syncer extends ZsyncObserver implements Observable { } @Override - public void controlFileDownloadingStarted(URI uri, long length) { - super.controlFileDownloadingStarted(uri, length); - System.out.println("controlFileDownloadingStarted " + length); + public void controlFileDownloadingStarted(Path path, long length) { + Logger.getLogger(getClass().getName()).log(Level.INFO, "controlFileDownloadingStarted " + length); SwingUtilities.invokeLater(() -> gui.syncStatusLabel.setText(currentDownload.getModPath() + ": Get Header")); } @Override - public void controlFileDownloadingComplete() { - super.controlFileDownloadingComplete(); - System.out.println("controlFileDownloadingComplete"); - controlfile_downloaded = true; + public void controlFileReadingComplete() { - SwingUtilities.invokeLater(() -> gui.syncStatusLabel.setText(currentDownload.getModPath() + ": Hashing")); } @Override - public void remoteFileDownloadingStarted(URI uri, long length) { - super.remoteFileDownloadingStarted(uri, length); - System.out.println("remoteFileDownloadingStarted " + length); + public void outputFileWritingStarted(long length) { + SwingUtilities.invokeLater(() -> gui.syncStatusLabel.setText(currentDownload.getModPath() + ": Writing File")); + } - downloadSize = length; - downloadDownloaded = 0; - downloadStarted = System.nanoTime(); + @Override + public void outputFileWritingCompleted() { + } + + @Override + public void inputFileReadingStarted(Path inputFile, long length) { + SwingUtilities.invokeLater(() -> gui.syncStatusLabel.setText(currentDownload.getModPath() + ": Reading File")); + } + + @Override + public void inputFileReadingComplete() { + + } + + @Override + public void controlFileDownloadingComplete() { + Logger.getLogger(getClass().getName()).log(Level.INFO, "controlFileDownloadingComplete"); + } + + @Override + public void remoteFileDownloadingInitiated(List ranges) { + downloadStarted = System.currentTimeMillis(); + Logger.getLogger(getClass().getName()).log(Level.INFO, "remoteFileDownloadingInitiated"); SwingUtilities.invokeLater(() -> gui.syncStatusLabel.setText(currentDownload.getModPath() + ": Downloading")); } @Override - public void bytesDownloaded(long bytes) { - super.bytesDownloaded(bytes); - downloadDownloaded += bytes; + public void remoteFileDownloadingStarted(long length) { + downloadDownloaded = 0; + downloadSize = length; - if (controlfile_downloaded) { - final int percentage = (int) (((double) downloadDownloaded / (double) downloadSize) * 100); - SwingUtilities.invokeLater(() -> { - gui.syncFileProgress.setValue(percentage); - gui.syncFileProgress.setString(percentage + " % " + Humanize.binaryPrefix(downloadDownloaded) + "/" + currentDownload_sizeS); - }); - } + Logger.getLogger(getClass().getName()).log(Level.INFO, "remoteFileDownloadingStarted " + length); } + @Override + public void remoteFileDownloadingComplete() { + Logger.getLogger(getClass().getName()).log(Level.INFO, "remoteFileDownloadingStarted"); + } + + @Override + public void bytesDownloaded(long bytes) { + downloadDownloaded += bytes; + } public boolean isStopped() { return stopped; diff --git a/src/main/java/de/mc8051/arma3launcher/repo/Updater.java b/src/main/java/de/mc8051/arma3launcher/repo/Updater.java new file mode 100644 index 0000000..5ea3e1a --- /dev/null +++ b/src/main/java/de/mc8051/arma3launcher/repo/Updater.java @@ -0,0 +1,33 @@ +package de.mc8051.arma3launcher.repo; + +import de.mc8051.arma3launcher.ArmA3Launcher; +import de.mc8051.arma3launcher.utils.Callback; + +/** + * Created by gurkengewuerz.de on 29.03.2020. + */ +public class Updater { + + private boolean canPatch = false; + + public void update() { + + } + + public void getNewestVersion(Callback.HttpCallback callback) { + RepositoryManger.getInstance().getAsync(ArmA3Launcher.config.getString("sync.url") + "/.sync/version.txt", callback); + } + + public void needUpdate(Callback.NeedUpdateCallback callback) { + final Version currentVersion = new Version(ArmA3Launcher.VERSION); + getNewestVersion(new Callback.HttpCallback() { + @Override + public void response(Response r) { + if (!r.isSuccessful()) callback.response(false, null); + final String[] split = r.getBody().split(":"); + final Version newestVersion = new Version(r.getBody().split(":")[0]); + callback.response((currentVersion.compareTo(newestVersion) < 0), newestVersion); + } + }); + } +} diff --git a/src/main/java/de/mc8051/arma3launcher/repo/Version.java b/src/main/java/de/mc8051/arma3launcher/repo/Version.java new file mode 100644 index 0000000..24add50 --- /dev/null +++ b/src/main/java/de/mc8051/arma3launcher/repo/Version.java @@ -0,0 +1,50 @@ +package de.mc8051.arma3launcher.repo; + +public class Version implements Comparable { + + private String version; + + public final String get() { + return this.version; + } + + public Version(String version) { + if (version == null) + throw new IllegalArgumentException("Version can not be null"); + if (!version.matches("[0-9]+(\\.[0-9]+)*")) + throw new IllegalArgumentException("Invalid version format"); + this.version = version; + } + + @Override + public int compareTo(Version that) { + if (that == null) + return 1; + String[] thisParts = this.get().split("\\."); + String[] thatParts = that.get().split("\\."); + int length = Math.max(thisParts.length, thatParts.length); + for (int i = 0; i < length; i++) { + int thisPart = i < thisParts.length ? + Integer.parseInt(thisParts[i]) : 0; + int thatPart = i < thatParts.length ? + Integer.parseInt(thatParts[i]) : 0; + if (thisPart < thatPart) + return -1; + if (thisPart > thatPart) + return 1; + } + return 0; + } + + @Override + public boolean equals(Object that) { + if (this == that) + return true; + if (that == null) + return false; + if (this.getClass() != that.getClass()) + return false; + return this.compareTo((Version) that) == 0; + } + +} diff --git a/src/main/java/de/mc8051/arma3launcher/utils/Callback.java b/src/main/java/de/mc8051/arma3launcher/utils/Callback.java index 9ab2801..c7cacbc 100644 --- a/src/main/java/de/mc8051/arma3launcher/utils/Callback.java +++ b/src/main/java/de/mc8051/arma3launcher/utils/Callback.java @@ -1,6 +1,7 @@ package de.mc8051.arma3launcher.utils; import de.mc8051.arma3launcher.repo.Response; +import de.mc8051.arma3launcher.repo.Version; import java.io.File; @@ -20,4 +21,9 @@ public class Callback { public interface ChangelogCallback { void response(String changelog); } + + public interface NeedUpdateCallback { + void response(boolean needUpdate, Version newestVersion); + } + } diff --git a/src/main/resources/lang_de_DE.properties b/src/main/resources/lang_de_DE.properties index 7c59f9e..3c3a130 100644 --- a/src/main/resources/lang_de_DE.properties +++ b/src/main/resources/lang_de_DE.properties @@ -100,6 +100,8 @@ about= follow_on_twitter=Folgt und auf Twitter star_on_github="Star us" auf GitHub client_up_to_date=Client ist aktuell +client_outdated=Neue Client Version verfügbar +please_update=Bitte führe ein Update durch developer_page=Entwickler-Seite project_page=Projektseite fast_check=Schnelle Prüfung diff --git a/src/main/resources/lang_en_US.properties b/src/main/resources/lang_en_US.properties index 985be1e..9489689 100644 --- a/src/main/resources/lang_en_US.properties +++ b/src/main/resources/lang_en_US.properties @@ -98,6 +98,8 @@ about=About follow_on_twitter=Follow us on Twitter star_on_github=Star us on GitHub client_up_to_date=Client is up to date +client_outdated=New client version available +please_update=Please do an update developer_page=Developer page project_page=Project page new_modset_name=Modsset name