diff --git a/forge-core/src/main/java/forge/util/BuildInfo.java b/forge-core/src/main/java/forge/util/BuildInfo.java index 5393a62cdd9..b20327ab343 100644 --- a/forge-core/src/main/java/forge/util/BuildInfo.java +++ b/forge-core/src/main/java/forge/util/BuildInfo.java @@ -6,12 +6,12 @@ * 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 . */ @@ -20,19 +20,29 @@ package forge.util; import org.apache.commons.lang3.StringUtils; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.text.SimpleDateFormat; +import java.util.Date; + /** * Provides access to information about the current version and build ID. */ public class BuildInfo { + private static Date timestamp = null; + // disable instantiation - private BuildInfo() { } + private BuildInfo() { + } /** * Get the current version of Forge. - * + * * @return a String representing the version specifier, or "GIT" if unknown. */ - public static final String getVersionString() { + public static String getVersionString() { String version = BuildInfo.class.getPackage().getImplementationVersion(); if (StringUtils.isEmpty(version)) { return "GIT"; @@ -46,7 +56,41 @@ public class BuildInfo { StringUtils.containsIgnoreCase(forgeVersion, "snapshot"); } + public static Date getTimestamp() { + if (timestamp != null) + return timestamp; + try { + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + InputStream inputStream = BuildInfo.class.getResourceAsStream("/build.txt"); + String data = readFromInputStream(inputStream); + timestamp = simpleDateFormat.parse(data); + } catch (Exception e) { + e.printStackTrace(); + } + return timestamp; + } + + public static boolean verifyTimestamp(Date updateTimestamp) { + if (updateTimestamp == null) + return false; + if (getTimestamp() == null) + return false; + //System.err.println("Update Timestamp: " + updateTimestamp + "\nBuild Timestamp: " + getTimestamp()); + return updateTimestamp.after(getTimestamp()); + } + public static String getUserAgent() { return "Forge/" + getVersionString(); } + + private static String readFromInputStream(InputStream inputStream) throws IOException { + StringBuilder resultStringBuilder = new StringBuilder(); + try (BufferedReader br = new BufferedReader(new InputStreamReader(inputStream))) { + String line; + while ((line = br.readLine()) != null) { + resultStringBuilder.append(line).append("\n"); + } + } + return resultStringBuilder.toString(); + } } diff --git a/forge-gui-desktop/src/main/java/forge/control/FControl.java b/forge-gui-desktop/src/main/java/forge/control/FControl.java index fbd7d496816..d0aea495254 100644 --- a/forge-gui-desktop/src/main/java/forge/control/FControl.java +++ b/forge-gui-desktop/src/main/java/forge/control/FControl.java @@ -27,7 +27,9 @@ import java.awt.event.WindowEvent; import java.io.File; import java.io.IOException; import java.net.URL; +import java.text.SimpleDateFormat; import java.util.Collections; +import java.util.Date; import java.util.List; import javax.swing.ImageIcon; @@ -88,7 +90,8 @@ public enum FControl implements KeyEventDispatcher { private CloseAction closeAction; private final List currentMatches = Lists.newArrayList(); private String snapsVersion = "", currentVersion = ""; - private boolean isSnapshot; + private Date snapsTimestamp = null, buildTimeStamp = null; + private boolean isSnapshot, hasSnapsUpdate; private Localizer localizer; public enum CloseAction { @@ -139,31 +142,33 @@ public enum FControl implements KeyEventDispatcher { @Override public void windowClosing(final WindowEvent e) { switch (closeAction) { - case NONE: //prompt user for close action if not previously specified - final List options = ImmutableList.of(getLocalizer().getMessage("lblCloseScreen"), getLocalizer().getMessage("lblExitForge"), getLocalizer().getMessage("lblCancel")); - final int reply = FOptionPane.showOptionDialog( - getLocalizer().getMessage("txCloseAction1") + "\n\n" + getLocalizer().getMessage("txCloseAction2"), - getLocalizer().getMessage("titCloseAction"), - FOptionPane.INFORMATION_ICON, - options, - 2); - switch (reply) { - case 0: //Close Screen - setCloseAction(CloseAction.CLOSE_SCREEN); - windowClosing(e); //call again to apply chosen close action - return; - case 1: //Exit Forge - setCloseAction(CloseAction.EXIT_FORGE); - windowClosing(e); //call again to apply chosen close action - return; - } - break; - case CLOSE_SCREEN: - Singletons.getView().getNavigationBar().closeSelectedTab(); - break; - case EXIT_FORGE: - if (exitForge()) { return; } - break; + case NONE: //prompt user for close action if not previously specified + final List options = ImmutableList.of(getLocalizer().getMessage("lblCloseScreen"), getLocalizer().getMessage("lblExitForge"), getLocalizer().getMessage("lblCancel")); + final int reply = FOptionPane.showOptionDialog( + getLocalizer().getMessage("txCloseAction1") + "\n\n" + getLocalizer().getMessage("txCloseAction2"), + getLocalizer().getMessage("titCloseAction"), + FOptionPane.INFORMATION_ICON, + options, + 2); + switch (reply) { + case 0: //Close Screen + setCloseAction(CloseAction.CLOSE_SCREEN); + windowClosing(e); //call again to apply chosen close action + return; + case 1: //Exit Forge + setCloseAction(CloseAction.EXIT_FORGE); + windowClosing(e); //call again to apply chosen close action + return; + } + break; + case CLOSE_SCREEN: + Singletons.getView().getNavigationBar().closeSelectedTab(); + break; + case EXIT_FORGE: + if (exitForge()) { + return; + } + break; } //prevent closing Forge if we reached this point Singletons.getView().getFrame().setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); @@ -171,12 +176,22 @@ public enum FControl implements KeyEventDispatcher { }); } + public Date getBuildTimeStamp() { + return buildTimeStamp; + } + + public Date getSnapsTimestamp() { + return snapsTimestamp; + } + public CloseAction getCloseAction() { return closeAction; } public void setCloseAction(final CloseAction closeAction0) { - if (closeAction == closeAction0) { return; } + if (closeAction == closeAction0) { + return; + } closeAction = closeAction0; Singletons.getView().getNavigationBar().updateBtnCloseTooltip(); @@ -187,7 +202,7 @@ public enum FControl implements KeyEventDispatcher { public boolean canExitForge(final boolean forRestart) { final String action = (forRestart ? getLocalizer().getMessage("lblRestart") : getLocalizer().getMessage("lblExit")); - String userPrompt =(forRestart ? getLocalizer().getMessage("lblAreYouSureYouWishRestartForge") : getLocalizer().getMessage("lblAreYouSureYouWishExitForge")); + String userPrompt = (forRestart ? getLocalizer().getMessage("lblAreYouSureYouWishRestartForge") : getLocalizer().getMessage("lblAreYouSureYouWishExitForge")); final boolean hasCurrentMatches = hasCurrentMatches(); if (hasCurrentMatches) { userPrompt = getLocalizer().getMessage("lblOneOrMoreGamesActive") + ". " + userPrompt; @@ -219,7 +234,9 @@ public enum FControl implements KeyEventDispatcher { return true; } - /** After view and model have been initialized, control can start.*/ + /** + * After view and model have been initialized, control can start. + */ public void initialize() { final ForgePreferences prefs = FModel.getPreferences(); currentVersion = BuildInfo.getVersionString(); @@ -229,9 +246,15 @@ public enum FControl implements KeyEventDispatcher { if (isSnapshot && prefs.getPrefBoolean(FPref.CHECK_SNAPSHOT_AT_STARTUP)) { URL url = new URL("https://downloads.cardforge.org/dailysnapshots/version.txt"); snapsVersion = FileUtil.readFileToString(url); + url = new URL("https://downloads.cardforge.org/dailysnapshots/build.txt"); + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + snapsTimestamp = simpleDateFormat.parse(FileUtil.readFileToString(url)); + buildTimeStamp = BuildInfo.getTimestamp(); + hasSnapsUpdate = BuildInfo.verifyTimestamp(snapsTimestamp); } - } catch (Exception ignored) {} + } catch (Exception ignored) { + } // Preloads skin components (using progress bar). FSkin.loadFull(true); @@ -251,15 +274,16 @@ public enum FControl implements KeyEventDispatcher { if (data.exists()) { try { FModel.getQuest().load(QuestDataIO.loadData(data)); - } catch(IOException ex) { + } catch (IOException ex) { ex.printStackTrace(); System.err.printf("Error loading quest data (%s).. skipping for now..%n", questname); } } // format release notes upon loading try { - TextUtil.getFormattedChangelog(new File(FileUtil.pathCombine(System.getProperty("user.dir"), ForgeConstants.CHANGES_FILE_NO_RELEASE)),""); - } catch (Exception e){} + TextUtil.getFormattedChangelog(new File(FileUtil.pathCombine(System.getProperty("user.dir"), ForgeConstants.CHANGES_FILE_NO_RELEASE)), ""); + } catch (Exception e) { + } // Handles resizing in null layouts of layers in JLayeredPane as well as saving window layout final FFrame window = Singletons.getView().getFrame(); window.addComponentListener(new ComponentAdapter() { @@ -284,11 +308,13 @@ public enum FControl implements KeyEventDispatcher { FView.SINGLETON_INSTANCE.setSplashProgessBarMessage(getLocalizer().getMessage("lblOpeningMainWindow")); SwingUtilities.invokeLater(() -> Singletons.getView().initialize()); } + public boolean isSnapshot() { return isSnapshot; } + public String getSnapshotNotification() { - if (!isSnapshot || snapsVersion.isEmpty() || currentVersion.equalsIgnoreCase(snapsVersion)) + if (!isSnapshot || !hasSnapsUpdate || snapsVersion.isEmpty()) return ""; return getLocalizer().getMessage("lblNewSnapshotVersion", snapsVersion); } @@ -315,6 +341,7 @@ public enum FControl implements KeyEventDispatcher { public boolean setCurrentScreen(final FScreen screen) { return setCurrentScreen(screen, false); } + public boolean setCurrentScreen(final FScreen screen, final boolean previousScreenClosed) { //TODO: Uncomment the line below if this function stops being used to refresh //the current screen in some places (such as Continue and Restart in the match screen) @@ -363,11 +390,11 @@ public enum FControl implements KeyEventDispatcher { FView.SINGLETON_INSTANCE.getPnlInsets().setForegroundImage(FSkin.getIcon(FSkinProp.BG_NIGHT), true); } } else { - FView.SINGLETON_INSTANCE.getPnlInsets().setForegroundImage((Image)null); + FView.SINGLETON_INSTANCE.getPnlInsets().setForegroundImage((Image) null); } //SOverlayUtils.showTargetingOverlay(); } else { - FView.SINGLETON_INSTANCE.getPnlInsets().setForegroundImage((Image)null); + FView.SINGLETON_INSTANCE.getPnlInsets().setForegroundImage((Image) null); } Singletons.getView().getNavigationBar().updateSelectedTab(); @@ -379,12 +406,16 @@ public enum FControl implements KeyEventDispatcher { } public boolean ensureScreenActive(final FScreen screen) { - if (currentScreen == screen) { return true; } + if (currentScreen == screen) { + return true; + } return setCurrentScreen(screen); } - /** Remove all children from a specified layer. */ + /** + * Remove all children from a specified layer. + */ private void clearChildren(final int layer0) { final Component[] children = FView.SINGLETON_INSTANCE.getLpnDocument().getComponentsInLayer(layer0); @@ -393,16 +424,24 @@ public enum FControl implements KeyEventDispatcher { } } - /** Sizes children of JLayeredPane to fully fit their layers. */ + /** + * Sizes children of JLayeredPane to fully fit their layers. + */ private void sizeChildren() { Component[] children = display.getComponentsInLayer(JLayeredPane.DEFAULT_LAYER); - if (children.length != 0) { children[0].setSize(display.getSize()); } + if (children.length != 0) { + children[0].setSize(display.getSize()); + } children = display.getComponentsInLayer(FView.TARGETING_LAYER); - if (children.length != 0) { children[0].setSize(display.getSize()); } + if (children.length != 0) { + children[0].setSize(display.getSize()); + } children = display.getComponentsInLayer(JLayeredPane.MODAL_LAYER); - if (children.length != 0) { children[0].setSize(display.getSize()); } + if (children.length != 0) { + children[0].setSize(display.getSize()); + } } public Dimension getDisplaySize() { @@ -421,18 +460,15 @@ public enum FControl implements KeyEventDispatcher { forgeMenu.show(true); return true; } - } - else if (e.getID() == KeyEvent.KEY_PRESSED && e.getModifiersEx() == InputEvent.ALT_DOWN_MASK) { + } else if (e.getID() == KeyEvent.KEY_PRESSED && e.getModifiersEx() == InputEvent.ALT_DOWN_MASK) { altKeyLastDown = true; } - } - else { + } else { altKeyLastDown = false; if (e.getID() == KeyEvent.KEY_PRESSED) { //give Forge menu the chance to handle the key event return forgeMenu.handleKeyEvent(e); - } - else if (e.getID() == KeyEvent.KEY_RELEASED) { + } else if (e.getID() == KeyEvent.KEY_RELEASED) { if (e.getKeyCode() == KeyEvent.VK_CONTEXT_MENU) { forgeMenu.show(); } diff --git a/forge-gui-desktop/src/main/java/forge/screens/home/settings/CSubmenuDownloaders.java b/forge-gui-desktop/src/main/java/forge/screens/home/settings/CSubmenuDownloaders.java index cff8d450da9..62edd9c1b0f 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/home/settings/CSubmenuDownloaders.java +++ b/forge-gui-desktop/src/main/java/forge/screens/home/settings/CSubmenuDownloaders.java @@ -2,6 +2,7 @@ package forge.screens.home.settings; import javax.swing.SwingUtilities; +import forge.control.FControl; import forge.download.AutoUpdater; import forge.download.GuiDownloader; import forge.gui.ImportDialog; @@ -32,7 +33,7 @@ public enum CSubmenuDownloaders implements ICDoc { SINGLETON_INSTANCE; private final UiCommand cmdLicensing = VSubmenuDownloaders.SINGLETON_INSTANCE::showLicensing; - private final UiCommand cmdCheckForUpdates = () -> new AutoUpdater(false).attemptToUpdate(CompletableFuture.supplyAsync(() -> RSSReader.getCommitLog(GITHUB_COMMITS_URL_ATOM, null, null))); + private final UiCommand cmdCheckForUpdates = () -> new AutoUpdater(false).attemptToUpdate(CompletableFuture.supplyAsync(() -> RSSReader.getCommitLog(GITHUB_COMMITS_URL_ATOM, FControl.instance.getBuildTimeStamp(), FControl.instance.getSnapsTimestamp()))); private final UiCommand cmdPicDownload = () -> new GuiDownloader(new GuiDownloadPicturesLQ()).show(); private final UiCommand cmdPicDownloadHQ = () -> new GuiDownloader(new GuiDownloadPicturesHQ()).show(); diff --git a/forge-gui-desktop/src/main/java/forge/view/FTitleBarBase.java b/forge-gui-desktop/src/main/java/forge/view/FTitleBarBase.java index efae38f2f95..60ed4bc7c47 100644 --- a/forge-gui-desktop/src/main/java/forge/view/FTitleBarBase.java +++ b/forge-gui-desktop/src/main/java/forge/view/FTitleBarBase.java @@ -433,16 +433,21 @@ public abstract class FTitleBarBase extends SkinnedMenuBar { setPreferredSize(new Dimension(160, 25)); updateVisibility(); } + @Override protected void onClick() { - try { - new AutoUpdater(false).attemptToUpdate(CompletableFuture.supplyAsync(() -> RSSReader.getCommitLog(GITHUB_COMMITS_URL_ATOM, null, null))); - } catch (Exception e) { - e.printStackTrace(); + if (!displayText.isEmpty()) { + try { + new AutoUpdater(false).attemptToUpdate(CompletableFuture.supplyAsync(() -> RSSReader.getCommitLog(GITHUB_COMMITS_URL_ATOM, FControl.instance.getBuildTimeStamp(), FControl.instance.getSnapsTimestamp()))); + } catch (Exception e) { + e.printStackTrace(); + } } } @Override public void paintComponent(Graphics g) { + if (displayText.isEmpty()) + return; g.translate(-((int)((System.currentTimeMillis() / MARQUEE_SPEED_DIV) % ((getWidth() + wMod) * 2)) - (getWidth() + wMod)), 0); super.paintComponent(g); int thickness = 2; diff --git a/forge-gui-mobile/src/forge/assets/AssetsDownloader.java b/forge-gui-mobile/src/forge/assets/AssetsDownloader.java index ff736e80d99..6bed654c79c 100644 --- a/forge-gui-mobile/src/forge/assets/AssetsDownloader.java +++ b/forge-gui-mobile/src/forge/assets/AssetsDownloader.java @@ -3,14 +3,12 @@ package forge.assets; import java.io.IOException; import java.net.URL; import java.text.SimpleDateFormat; -import java.util.Calendar; import java.util.Date; import java.util.List; -import java.util.TimeZone; import com.badlogic.gdx.files.FileHandle; import forge.gui.GuiBase; -import forge.util.TextUtil; +import forge.util.BuildInfo; import org.apache.commons.lang3.StringUtils; import com.badlogic.gdx.Gdx; @@ -30,7 +28,6 @@ public class AssetsDownloader { private final static ImmutableList downloadIgnoreExit = ImmutableList.of("Download", "Ignore", "Exit"); private final static ImmutableList downloadExit = ImmutableList.of("Download", "Exit"); - //if not sharing desktop assets, check whether assets are up to date public static void checkForUpdates(boolean exited, Runnable runnable) { if (exited) return; @@ -52,7 +49,11 @@ public class AssetsDownloader { final String versionText = isSnapshots ? snapsURL + "version.txt" : releaseURL + "version.txt"; FileHandle assetsDir = Gdx.files.absolute(ForgeConstants.ASSETS_DIR); FileHandle resDir = Gdx.files.absolute(ForgeConstants.RES_DIR); + FileHandle buildTxtFileHandle = Gdx.files.classpath("build.txt"); + final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + boolean verifyUpdatable = false; boolean mandatory = false; + Date snapsTimestamp = null, buildTimeStamp; String message; boolean connectedToInternet = Forge.getDeviceAdapter().isConnectedToInternet(); @@ -74,31 +75,30 @@ public class AssetsDownloader { String snapsBZ2URL = "https://downloads.cardforge.org/dailysnapshots/"; installerURL = isSnapshots ? snapsBZ2URL : releaseBZ2URL; } - //TODO build version - /*String buildver = ""; - SimpleDateFormat DateFor = TextUtil.getSimpleDate(); - Calendar calendar = Calendar.getInstance(); - Date buildDateOriginal = null; - try { - FileHandle build = Gdx.files.classpath("build.txt"); - if (build.exists()) { - SimpleDateFormat original = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - original.setTimeZone(TimeZone.getTimeZone("UTC")); - Date buildDate = original.parse(build.readString()); - buildDateOriginal = original.parse(build.readString()); - calendar.setTime(buildDate); - DateFor.setTimeZone(TimeZone.getDefault()); - buildver = "\nForge Build: " + DateFor.format(calendar.getTime()); + String snapsBuildDate = "", buildDate = ""; + if (isSnapshots) { + URL url = new URL(snapsURL + "build.txt"); + snapsTimestamp = format.parse(FileUtil.readFileToString(url)); + snapsBuildDate = snapsTimestamp.toString(); + if (!GuiBase.isAndroid()) { + buildDate = BuildInfo.getTimestamp().toString(); + verifyUpdatable = BuildInfo.verifyTimestamp(snapsTimestamp); + } else { + if (buildTxtFileHandle.exists()) { + buildTimeStamp = format.parse(buildTxtFileHandle.readString()); + buildDate = buildTimeStamp.toString(); + verifyUpdatable = snapsTimestamp.after(buildTimeStamp); + } } - } catch (Exception e) { - e.printStackTrace(); - }*/ + } else { + verifyUpdatable = !StringUtils.isEmpty(version) && !versionString.equals(version); + } - if (!StringUtils.isEmpty(version) && !versionString.equals(version)) { + if (verifyUpdatable) { Forge.getSplashScreen().prepareForDialogs(); - message = "A new version of Forge is available (" + version + ").\n" + - "You are currently on an older version (" + versionString + ").\n\n" + + message = "A new version of Forge is available. - v." + version + "\n" + snapsBuildDate + "\n" + + "You are currently on an older version. - v." + versionString + "\n" + buildDate + "\n" + "Would you like to update to the new version now?"; if (!Forge.getDeviceAdapter().isConnectedToWifi()) { message += " If so, you may want to connect to wifi first. The download is around " + (GuiBase.isAndroid() ? apkSize : packageSize) + "."; @@ -130,8 +130,10 @@ public class AssetsDownloader { } } } else { - if (!GuiBase.isAndroid()) + if (!GuiBase.isAndroid()) { run(runnable); + return; + } } } catch (Exception e) { e.printStackTrace(); @@ -181,30 +183,21 @@ public class AssetsDownloader { return; //if version matches what had been previously saved and FSkin isn't requesting assets download, no need to download assets } - FileHandle f = Gdx.files.classpath("build.txt"); - FileHandle t = resDir.child("build.txt"); - if (f.exists() && t.exists()) { - String buildString = f.readString(); - String target = t.readString(); + FileHandle resBuildDate = resDir.child("build.txt"); + if (buildTxtFileHandle.exists() && resBuildDate.exists()) { + String buildString = buildTxtFileHandle.readString(); + String target = resBuildDate.readString(); try { - Date buildDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(buildString); - Date targetDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(target); + Date buildDate = format.parse(buildString); + Date targetDate = format.parse(target); // if res folder has same build date then continue loading assets if (buildDate.equals(targetDate) && versionString.equals(FileUtil.readFileToString(versionFile.file()))) { run(runnable); return; } mandatory = true; - //format to local date - SimpleDateFormat original = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - original.setTimeZone(TimeZone.getTimeZone("UTC")); - targetDate = original.parse(target); - Calendar calendar = Calendar.getInstance(); - calendar.setTime(targetDate); - SimpleDateFormat simpleDate = TextUtil.getSimpleDate(); - simpleDate.setTimeZone(TimeZone.getDefault()); - build += "Installed resources date: " + simpleDate.format(calendar.getTime()) + "\n\n"; - log = Forge.getDeviceAdapter().getLatestChanges(GITHUB_COMMITS_URL_ATOM, null, null); + build += "\nInstalled resources date:\n" + target + "\n"; + log = Forge.getDeviceAdapter().getLatestChanges(GITHUB_COMMITS_URL_ATOM, buildDate, snapsTimestamp); } catch (Exception e) { e.printStackTrace(); } diff --git a/forge-gui/src/main/java/forge/download/AutoUpdater.java b/forge-gui/src/main/java/forge/download/AutoUpdater.java index 008e8563166..a37443bd436 100644 --- a/forge-gui/src/main/java/forge/download/AutoUpdater.java +++ b/forge-gui/src/main/java/forge/download/AutoUpdater.java @@ -9,6 +9,8 @@ import java.net.Socket; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; +import java.text.SimpleDateFormat; +import java.util.Date; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; @@ -29,6 +31,7 @@ import forge.model.FModel; import forge.util.BuildInfo; import forge.util.FileUtil; import forge.util.Localizer; +import forge.util.TextUtil; import forge.util.WaitCallback; public class AutoUpdater { @@ -46,6 +49,8 @@ public class AutoUpdater { private String versionUrlString; private String packageUrl; private String packagePath; + private String buildDate = ""; + private String snapsBuildDate = ""; public AutoUpdater(boolean loading) { // What do I need? Preferences? Splashscreen? UI? Skins? @@ -133,7 +138,14 @@ public class AutoUpdater { private boolean compareBuildWithLatestChannelVersion() { try { retrieveVersion(); - + if (buildVersion.contains("SNAPSHOT")) { + URL url = new URL("https://downloads.cardforge.org/dailysnapshots/build.txt"); + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + Date snapsTimestamp = simpleDateFormat.parse(FileUtil.readFileToString(url)); + snapsBuildDate = snapsTimestamp.toString(); + buildDate = BuildInfo.getTimestamp().toString(); + return BuildInfo.verifyTimestamp(snapsTimestamp); + } if (StringUtils.isEmpty(version) ) { return false; } @@ -143,7 +155,7 @@ public class AutoUpdater { } } catch (Exception e) { - e.printStackTrace(); + SOptionPane.showOptionDialog(e.getMessage(), localizer.getMessage("lblError"), null, ImmutableList.of("Ok")); return false; } // If version doesn't match, it's assummably newer. @@ -183,8 +195,10 @@ public class AutoUpdater { // splashScreen.prepareForDialogs(); return downloadFromBrowser(); } - String log = cf.get(); - String message = localizer.getMessage("lblNewVersionForgeAvailableUpdateConfirm", version, buildVersion) + log; + String logs = snapsBuildDate.isEmpty() ? "" : cf.get(); + String v = snapsBuildDate.isEmpty() ? version : version + TextUtil.enclosedParen(snapsBuildDate); + String b = buildDate.isEmpty() ? buildVersion : buildVersion + TextUtil.enclosedParen(buildDate); + String message = localizer.getMessage("lblNewVersionForgeAvailableUpdateConfirm", v, b) + logs; final List options = ImmutableList.of(localizer.getMessage("lblUpdateNow"), localizer.getMessage("lblUpdateLater")); if (SOptionPane.showOptionDialog(message, localizer.getMessage("lblNewVersionAvailable"), null, options, 0) == 0) { return downloadFromForge();