Browse Source

Updated error handling to survive server outages

master
JellySquid 3 years ago
parent
commit
d54b7bcdeb
25 changed files with 362 additions and 125 deletions
  1. 0
    1
      launcher-aether/config.json
  2. 20
    6
      launcher-aether/src/main/java/com/gildedgames/launcher/ui/components/FlatButton.java
  3. 56
    20
      launcher-aether/src/main/java/com/gildedgames/launcher/ui/components/NewsElement.java
  4. 83
    0
      launcher-aether/src/main/java/com/gildedgames/launcher/ui/panels/BannerPanel.java
  5. 8
    1
      launcher-aether/src/main/java/com/gildedgames/launcher/ui/panels/ProgressIndicatorPanel.java
  6. 13
    3
      launcher-aether/src/main/java/com/gildedgames/launcher/ui/resources/CacheManager.java
  7. 29
    15
      launcher-aether/src/main/java/com/gildedgames/launcher/ui/resources/LauncherIcons.java
  8. 64
    37
      launcher-aether/src/main/java/com/gildedgames/launcher/ui/resources/NewsFeedManager.java
  9. 2
    2
      launcher-aether/src/main/java/com/gildedgames/launcher/ui/views/OptionsView.java
  10. 83
    32
      launcher-aether/src/main/java/com/gildedgames/launcher/ui/views/game/PlayView.java
  11. 0
    0
      launcher-aether/src/main/resources/com/gildedgames/assets/icons/16/add.png
  12. 0
    0
      launcher-aether/src/main/resources/com/gildedgames/assets/icons/16/bug.png
  13. 0
    0
      launcher-aether/src/main/resources/com/gildedgames/assets/icons/16/close.png
  14. 0
    0
      launcher-aether/src/main/resources/com/gildedgames/assets/icons/16/gear.png
  15. 0
    0
      launcher-aether/src/main/resources/com/gildedgames/assets/icons/16/maximize.png
  16. 0
    0
      launcher-aether/src/main/resources/com/gildedgames/assets/icons/16/minimize.png
  17. 0
    0
      launcher-aether/src/main/resources/com/gildedgames/assets/icons/16/play.png
  18. 0
    0
      launcher-aether/src/main/resources/com/gildedgames/assets/icons/16/refresh.png
  19. 0
    0
      launcher-aether/src/main/resources/com/gildedgames/assets/icons/16/remove.png
  20. 0
    0
      launcher-aether/src/main/resources/com/gildedgames/assets/icons/16/switch_user.png
  21. BIN
      launcher-aether/src/main/resources/com/gildedgames/assets/icons/16/warn.png
  22. BIN
      launcher-aether/src/main/resources/com/gildedgames/assets/icons/64/warn.png
  23. 0
    2
      launcher-fancy/accounts.dat
  24. 0
    1
      launcher-fancy/config.json
  25. 4
    5
      launcher/src/main/java/com/skcraft/concurrency/ObservableFuture.java

+ 0
- 1
launcher-aether/config.json View File

@@ -1 +0,0 @@
{"offlineEnabled":true,"jvmPath":null,"jvmArgs":null,"minMemory":1024,"maxMemory":4096,"permGen":256,"windowWidth":854,"widowHeight":480,"proxyEnabled":false,"proxyHost":"localhost","proxyPort":8080,"proxyUsername":null,"proxyPassword":null,"gameKey":null}

+ 20
- 6
launcher-aether/src/main/java/com/gildedgames/launcher/ui/components/FlatButton.java View File

@@ -17,7 +17,7 @@ public class FlatButton extends JButton {
DISABLED(new Color(0x777777), new Color(0x777777), new Color(0x777777), new Color(0x444444)),
LIGHT(new Color(0x333d47), new Color(0x4d5c6b), new Color(0x333d47), Color.WHITE),
HIGHLIGHTED(new Color(0x2f68a2), new Color(0x3d8ee0), new Color(0x2f68a2), Color.WHITE),
TRANSPARENT(null, null, new Color(0x333d47), Color.WHITE);
TRANSPARENT(null, null, new Color(0, 0, 0, 40), Color.WHITE);

private final Color bgNormal, bgHover, bgPressed;

@@ -44,6 +44,10 @@ public class FlatButton extends JButton {
}
}

public enum AlignState {
LEFT, CENTER, RIGHT
}

@Getter
@Setter
private ImageIcon buttonIcon;
@@ -54,7 +58,7 @@ public class FlatButton extends JButton {

@Getter
@Setter
private boolean isLeftAligned;
private AlignState align = AlignState.CENTER;

private boolean hovered;

@@ -138,18 +142,28 @@ public class FlatButton extends JButton {
}

if (this.getButtonIcon() != null) {
int x;
int x = 0;

if (this.isLeftAligned()) {
if (this.getAlign() == AlignState.LEFT) {
x = 12;
} else {
} else if (this.getAlign() == AlignState.RIGHT) {
x = this.getWidth() - textWidth - 36;
} else if (this.getAlign() == AlignState.CENTER) {
x = (this.getWidth() / 2) - ((this.getButtonIcon().getIconWidth() + textWidth + 24) / 2) + 6;
}

g2.drawImage(this.getButtonIcon().getImage(), x, (this.getHeight() / 2) - (this.getButtonIcon().getIconHeight() / 2), null);
g2.drawString(this.getText(), x + 24, (this.getHeight() / 2) - (textHeight / 2) + fontMetrics.getAscent());
} else {
int x = this.isLeftAligned() ? 12 : (this.getWidth() / 2) - (textWidth / 2);
int x = 0;

if (this.getAlign() == AlignState.LEFT) {
x = 12;
} else if (this.getAlign() == AlignState.CENTER) {
x = (this.getWidth() / 2) - (textWidth / 2);
} else if (this.getAlign() == AlignState.RIGHT) {
x = this.getWidth() - textWidth - 24;
}

g2.drawString(this.getText(), x, (this.getHeight() / 2) - (textHeight / 2) + fontMetrics.getAscent());
}

+ 56
- 20
launcher-aether/src/main/java/com/gildedgames/launcher/ui/components/NewsElement.java View File

@@ -1,10 +1,15 @@
package com.gildedgames.launcher.ui.components;

import com.gildedgames.launcher.ui.resources.LauncherFonts;
import com.gildedgames.launcher.ui.resources.LauncherIcons;
import com.gildedgames.launcher.ui.resources.NewsFeedManager;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.skcraft.launcher.util.SwingExecutor;

import javax.annotation.Nullable;
import javax.swing.JComponent;
import javax.swing.SwingUtilities;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
@@ -15,10 +20,14 @@ import java.text.DateFormat;
import java.text.SimpleDateFormat;

public class NewsElement extends JComponent {
private static final Color TRANSPARENT = new Color(0, 0, 0, 1);
private static final Color TRANSPARENT = new Color(0, 0, 0, 1),
BACKGROUND = new Color(40, 40, 40);

private static final Font FONT_TITLE = LauncherFonts.OPEN_SANS_REGULAR.deriveFont(18.0f),
FONT_DATE = LauncherFonts.OPEN_SANS_REGULAR.deriveFont(12.0f);
FONT_DATE = LauncherFonts.OPEN_SANS_REGULAR.deriveFont(12.0f),
FONT_ERROR = LauncherFonts.OPEN_SANS_REGULAR.deriveFont(12.0f);

private static final Image WARNING_ICON = LauncherIcons.load("com/gildedgames/assets/icons/64/warn.png");

private static final DateFormat DATE_FORMAT = new SimpleDateFormat("MMMM dd, yyyy");

@@ -28,15 +37,31 @@ public class NewsElement extends JComponent {

private BufferedImage image;

private boolean failed;

public NewsElement(NewsFeedManager resourceCacheManager, NewsFeedManager.NewsDataElement data, boolean isSmall) {
this.data = data;

resourceCacheManager.getImage(data.getImages().get("launcher_preview"), value -> {
this.image = value;
ListenableFuture<NewsFeedManager.ImageResult> future = resourceCacheManager.getImage(data.getImages().get("launcher_preview"));

Futures.addCallback(future, new FutureCallback<NewsFeedManager.ImageResult>() {
@Override
public void onSuccess(@Nullable NewsFeedManager.ImageResult result) {
if (result == null) {
return;
}

SwingUtilities.invokeLater(this::repaint);
NewsElement.this.image = result.getImage();
}

@Override
public void onFailure(Throwable t) {
NewsElement.this.failed = true;
}
});

future.addListener(this::repaint, SwingExecutor.INSTANCE);

this.setPreferredSize(isSmall ? new Dimension(291, 145) : new Dimension(440, 220));

this.addMouseListener(new MouseAdapter() {
@@ -84,6 +109,31 @@ public class NewsElement extends JComponent {

if (this.image != null) {
g2.drawImage(this.image, 0, 0, this.getWidth(), this.getHeight(), null);
} else {
g2.setColor(BACKGROUND);
g2.fillRect(0, 0, this.getWidth(), this.getHeight());

if (this.failed) {
Composite prevComposite = g2.getComposite();

AlphaComposite composite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.3f);
g2.setComposite(composite);

g2.setFont(FONT_ERROR);

FontMetrics f = g2.getFontMetrics();

String str = "Failed to load image";

int width = f.stringWidth(str);

g2.drawImage(WARNING_ICON, (this.getWidth() / 2) - 32, (this.getHeight() / 2) - 32, null);
g2.setColor(Color.WHITE);

g2.drawString(str, (this.getWidth() / 2) - (width / 2), (this.getHeight() / 2) + 40);

g2.setComposite(prevComposite);
}
}

if (this.hovered) {
@@ -102,18 +152,4 @@ public class NewsElement extends JComponent {
g2.setColor(Color.LIGHT_GRAY);
g2.drawString(DATE_FORMAT.format(this.data.getDate()), 8, this.getHeight() - 12);
}
//
// private BufferedImage resizeImage(BufferedImage source, int targetWidth, int targetHeight) {
//
// BufferedImage dest = new BufferedImage(targetWidth, targetHeight, BufferedImage.TYPE_INT_RGB);
//
// Graphics2D g2 = (Graphics2D) dest.getGraphics();
// g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
// g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
// g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
//
// g2.drawImage(source, 0, 0, requiredWidth, requiredHeight, null);
//
// return dest;
// }
}

+ 83
- 0
launcher-aether/src/main/java/com/gildedgames/launcher/ui/panels/BannerPanel.java View File

@@ -0,0 +1,83 @@
package com.gildedgames.launcher.ui.panels;

import com.gildedgames.launcher.ui.components.FlatButton;
import com.gildedgames.launcher.ui.resources.LauncherFonts;
import com.gildedgames.launcher.ui.resources.LauncherIcons;
import net.miginfocom.swing.MigLayout;

import javax.swing.*;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class BannerPanel extends JPanel {
public enum BannerType {
INFO(new Color(0x455A64)),
ERROR(new Color(0xc62828));

private final Color color;

BannerType(Color color) {
this.color = color;
}
}

private boolean closeable = false;

private JLabel label, icon;

private FlatButton buttonAction;

private Runnable onClickRunnable;

public BannerPanel() {
this.initComponents();
}

private void initComponents() {
this.setLayout(new MigLayout("fill, insets 10 14 14 10", "[]8[]push[]", "[grow]"));

this.label = new JLabel();
this.label.setFont(LauncherFonts.OPEN_SANS_REGULAR.deriveFont(12.0f));
this.label.setForeground(Color.WHITE);

this.icon = new JLabel();

this.buttonAction = new FlatButton("Close", LauncherFonts.OPEN_SANS_REGULAR.deriveFont(12.0f));
this.buttonAction.setStyle(FlatButton.ButtonStyle.TRANSPARENT);
this.buttonAction.setPreferredSize(new Dimension(120, 24));
this.buttonAction.setAlign(FlatButton.AlignState.RIGHT);
this.buttonAction.setBorder(BorderFactory.createEmptyBorder());
this.buttonAction.addActionListener(e -> {
if (this.onClickRunnable != null) {
this.onClickRunnable.run();
}
});

this.add(icon);
this.add(label);
this.add(buttonAction);
}

public void update(ImageIcon icon, String text, BannerType type) {
this.label.setText(text);
this.icon.setIcon(icon);

this.setBackground(type.color);

this.bindActionHandler(null, "Close", null);

this.setVisible(true);
}

public void bindActionHandler(ImageIcon icon, String label, Runnable clickHandler) {
this.onClickRunnable = clickHandler;
this.buttonAction.setText(label);
this.buttonAction.setButtonIcon(icon);
}

public void close() {
this.setVisible(false);
}
}

+ 8
- 1
launcher-aether/src/main/java/com/gildedgames/launcher/ui/panels/ProgressIndicatorPanel.java View File

@@ -62,7 +62,10 @@ public class ProgressIndicatorPanel extends JPanel implements IProgressReporter

private void end() {
if (ProgressIndicatorPanel.this.future.isDone()) {
ProgressIndicatorPanel.this.updateTimer.cancel();
if (ProgressIndicatorPanel.this.updateTimer != null) {
ProgressIndicatorPanel.this.updateTimer.cancel();
ProgressIndicatorPanel.this.updateTimer = null;
}

ProgressIndicatorPanel.this.setVisible(false);
}
@@ -70,6 +73,10 @@ public class ProgressIndicatorPanel extends JPanel implements IProgressReporter
}, SwingExecutor.INSTANCE);

SwingUtilities.invokeLater(() -> {
if (ProgressIndicatorPanel.this.future.isDone()) {
return;
}

this.updateTimer = new Timer();
this.updateTimer.scheduleAtFixedRate(new ProgressIndicatorPanel.UpdateProgressTask(this), 10, 250);


+ 13
- 3
launcher-aether/src/main/java/com/gildedgames/launcher/ui/resources/CacheManager.java View File

@@ -1,12 +1,22 @@
package com.gildedgames.launcher.ui.resources;

import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class CacheManager {
private static final ExecutorService service = Executors.newSingleThreadExecutor();
private static final ListeningExecutorService service = MoreExecutors.listeningDecorator(Executors.newCachedThreadPool());

public static ListenableFuture<?> submitTask(Runnable runnable) {
return service.submit(runnable);
}

public static void submitTask(Runnable runnable) {
service.submit(runnable);
public static <T> ListenableFuture<T> submitTask(Callable<T> callable) {
return service.submit(callable);
}
}

+ 29
- 15
launcher-aether/src/main/java/com/gildedgames/launcher/ui/resources/LauncherIcons.java View File

@@ -5,6 +5,7 @@ import lombok.extern.java.Log;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import java.awt.Image;
import java.io.IOException;
import java.io.InputStream;

@@ -20,30 +21,42 @@ public class LauncherIcons {

public static final ImageIcon SWITCH_USER;

public static final ImageIcon BUG;
public static final ImageIcon BUG, WARN;

public static final ImageIcon WINDOW_MINIMIZE, WINDOW_CLOSE, WINDOW_MAXIMIZE;

public static final ImageIcon WINDOW_ICON;

static {
GEAR = load("com/gildedgames/assets/icons/gear.png");
ADD = load("com/gildedgames/assets/icons/add.png");
REMOVE = load("com/gildedgames/assets/icons/remove.png");
REFRESH = load("com/gildedgames/assets/icons/refresh.png");
PLAY = load("com/gildedgames/assets/icons/play.png");
GEAR = loadIcon("com/gildedgames/assets/icons/16/gear.png");
ADD = loadIcon("com/gildedgames/assets/icons/16/add.png");
REMOVE = loadIcon("com/gildedgames/assets/icons/16/remove.png");
REFRESH = loadIcon("com/gildedgames/assets/icons/16/refresh.png");
PLAY = loadIcon("com/gildedgames/assets/icons/16/play.png");

SWITCH_USER = load("com/gildedgames/assets/icons/switch_user.png");
BUG = load("com/gildedgames/assets/icons/bug.png");
SWITCH_USER = loadIcon("com/gildedgames/assets/icons/16/switch_user.png");
BUG = loadIcon("com/gildedgames/assets/icons/16/bug.png");
WARN = loadIcon("com/gildedgames/assets/icons/16/warn.png");

WINDOW_MINIMIZE = load("com/gildedgames/assets/icons/minimize.png");
WINDOW_CLOSE = load("com/gildedgames/assets/icons/close.png");
WINDOW_MAXIMIZE = load("com/gildedgames/assets/icons/maximize.png");
WINDOW_MINIMIZE = loadIcon("com/gildedgames/assets/icons/16/minimize.png");
WINDOW_CLOSE = loadIcon("com/gildedgames/assets/icons/16/close.png");
WINDOW_MAXIMIZE = loadIcon("com/gildedgames/assets/icons/16/maximize.png");

WINDOW_ICON = load("com/gildedgames/assets/titlebar/window-icon.png");
WINDOW_ICON = loadIcon("com/gildedgames/assets/titlebar/window-icon.png");
}

private static ImageIcon load(String path) {
public static ImageIcon loadIcon(String path) {
Image image = load(path);

if (image == null) {
return null;
}

return new ImageIcon(image);
}


public static Image load(String path) {
try {
InputStream stream = LauncherFrame.class.getClassLoader().getResourceAsStream(path);

@@ -51,10 +64,11 @@ public class LauncherIcons {
throw new IOException("Couldn't open stream");
}

return new ImageIcon(ImageIO.read(stream));
return ImageIO.read(stream);
} catch (IOException e) {
e.printStackTrace();
log.severe("Couldn't load icon " + path);

log.severe("Couldn't load image " + path);
}

return null;

+ 64
- 37
launcher-aether/src/main/java/com/gildedgames/launcher/ui/resources/NewsFeedManager.java View File

@@ -1,13 +1,19 @@
package com.gildedgames.launcher.ui.resources;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.skcraft.concurrency.Callback;
import com.skcraft.concurrency.ObservableFuture;
import com.skcraft.launcher.Launcher;
import com.skcraft.launcher.persistence.Persistence;
import com.skcraft.launcher.util.HttpRequest;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.apache.commons.io.IOUtils;

import javax.annotation.Nullable;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
@@ -17,6 +23,8 @@ import java.nio.file.Paths;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;

public class NewsFeedManager {
private static final String METADATA_URL = "https://files.gildedgames.com/minecraft/launcher/news/latest.json",
@@ -41,65 +49,75 @@ public class NewsFeedManager {
return manager;
}

public void refresh(Callback<NewsFeed> callback, boolean force) {
if (!force && this.feed.expires > System.currentTimeMillis()) {
if (callback != null) {
callback.handle(this.feed);
public ListenableFuture<NewsFeed> refresh(boolean force) {
ListenableFuture<NewsFeed> future = CacheManager.submitTask(() -> {
if (!force && NewsFeedManager.this.feed.expires > System.currentTimeMillis()) {
return null;
}

return;
}

CacheManager.submitTask(() -> {
try {
NewsFeed feed = HttpRequest.get(HttpRequest.url(METADATA_URL))
NewsFeed feed1 = HttpRequest.get(HttpRequest.url(METADATA_URL))
.execute()
.expectResponseCode(200)
.returnContent()
.asJson(NewsFeed.class);

feed.expires = System.currentTimeMillis() + CACHE_TIME;
feed1.expires = System.currentTimeMillis() + CACHE_TIME;
} catch (Exception e) {
e.printStackTrace();
}

return feed;
});

this.feed = feed;
Futures.addCallback(future, new FutureCallback<NewsFeed>() {
@Override
public void onSuccess(@Nullable NewsFeed result) {
NewsFeedManager.this.feed = result;
NewsFeedManager.this.save();
}

if (callback != null) {
callback.handle(feed);
}
@Override
public void onFailure(Throwable t) {

this.save();
} catch (Exception e) {
e.printStackTrace();
}
});
}

return future;
}

public void getImage(String resource, Callback<BufferedImage> callback) {
CacheManager.submitTask(() -> {
try {
byte[] data = this.tryLoadImage(resource);
public ListenableFuture<ImageResult> getImage(String resource) {
ListenableFuture<ImageResult> future = CacheManager.submitTask(() -> {
byte[] data = this.tryLoadImage(resource);

if (data == null) {
data = HttpRequest.get(HttpRequest.url(IMAGE_PROVIDER_URL + resource))
.execute()
.expectResponseCode(200)
.returnContent()
.asBytes();
}
if (data == null) {
data = HttpRequest.get(HttpRequest.url(IMAGE_PROVIDER_URL + resource))
.execute()
.expectResponseCode(200)
.returnContent()
.asBytes();
}

BufferedImage image;
BufferedImage image;

try (ByteArrayInputStream input = new ByteArrayInputStream(data)) {
image = ImageIO.read(input);
}
try (ByteArrayInputStream input = new ByteArrayInputStream(data)) {
image = ImageIO.read(input);
}

callback.handle(image);
return new ImageResult(image, data);
});

this.trySaveImage(resource, data);
} catch (Exception e) {
e.printStackTrace();
Futures.addCallback(future, new FutureCallback<ImageResult>() {
@Override
public void onSuccess(@Nullable ImageResult result) {
NewsFeedManager.this.trySaveImage(resource, result.getData());
}

@Override
public void onFailure(Throwable t) { }
});

return future;
}

private byte[] tryLoadImage(String resource) {
@@ -143,6 +161,15 @@ public class NewsFeedManager {
Persistence.commitAndForget(this);
}

@AllArgsConstructor
public static class ImageResult {
@Getter
private final BufferedImage image;

@Getter
private final byte[] data;
}

public static class NewsFeed {
@JsonProperty
@Getter

+ 2
- 2
launcher-aether/src/main/java/com/gildedgames/launcher/ui/views/OptionsView.java View File

@@ -150,8 +150,8 @@ public class OptionsView extends JPanel {
this.add(dataDirectoryString, c);

c.ipady = 0;
c.gridx = 2;
c.gridy = 1;
c.gridx = 0;
c.gridy = 2;
c.weightx = 0.0D;
c.weighty = 1.0D;
c.anchor = GridBagConstraints.WEST;

+ 83
- 32
launcher-aether/src/main/java/com/gildedgames/launcher/ui/views/game/PlayView.java View File

@@ -6,15 +6,16 @@ import com.gildedgames.launcher.ui.LauncherFrame;
import com.gildedgames.launcher.ui.components.FlatButton;
import com.gildedgames.launcher.ui.components.NewsElement;
import com.gildedgames.launcher.ui.components.UserIndicator;
import com.gildedgames.launcher.ui.panels.BannerPanel;
import com.gildedgames.launcher.ui.panels.ImagePanel;
import com.gildedgames.launcher.ui.panels.ProgressIndicatorPanel;
import com.gildedgames.launcher.ui.resources.LauncherFonts;
import com.gildedgames.launcher.ui.resources.LauncherIcons;
import com.gildedgames.launcher.ui.resources.NewsFeedManager;
import com.gildedgames.launcher.ui.views.ProgressView;
import com.gildedgames.launcher.ui.views.account.AccountListView;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.skcraft.concurrency.ObservableFuture;
import com.skcraft.concurrency.ProgressObservable;
import com.skcraft.launcher.Instance;
@@ -31,6 +32,7 @@ import com.skcraft.launcher.util.SwingExecutor;
import lombok.Getter;
import net.miginfocom.swing.MigLayout;

import javax.annotation.Nullable;
import javax.swing.*;
import java.awt.BorderLayout;
import java.awt.Color;
@@ -64,6 +66,10 @@ public class PlayView extends JPanel {

private ProgressIndicatorPanel progressIndicatorPanel;

private BannerPanel bannerPanel;

private JPanel news;

@Getter
private ConsolePanel consolePanel;

@@ -83,7 +89,7 @@ public class PlayView extends JPanel {

this.init();

SwingUtilities.invokeLater(this::loadInstances);
SwingUtilities.invokeLater(this::refresh);
}

private void init() {
@@ -97,7 +103,7 @@ public class PlayView extends JPanel {
this.switchUserButton = new FlatButton("Switch user", LauncherFonts.OPEN_SANS_REGULAR.deriveFont(12.0f));
this.switchUserButton.setStyle(FlatButton.ButtonStyle.TRANSPARENT);
this.switchUserButton.setButtonIcon(LauncherIcons.SWITCH_USER);
this.switchUserButton.setLeftAligned(true);
this.switchUserButton.setAlign(FlatButton.AlignState.LEFT);
this.switchUserButton.setBorder(BorderFactory.createEmptyBorder(9, 9, 9, 9));

this.selfUpdateButton = new FlatButton(SharedLocale.tr("launcher.updateLauncher"), LauncherFonts.OPEN_SANS_REGULAR.deriveFont(12.0f));
@@ -108,7 +114,7 @@ public class PlayView extends JPanel {
FlatButton optionsButton = new FlatButton("Options", LauncherFonts.OPEN_SANS_REGULAR.deriveFont(12.0f));
optionsButton.setBorder(BorderFactory.createEmptyBorder(9, 9, 9, 9));
optionsButton.setStyle(FlatButton.ButtonStyle.TRANSPARENT);
optionsButton.setLeftAligned(true);
optionsButton.setAlign(FlatButton.AlignState.LEFT);
optionsButton.setButtonIcon(LauncherIcons.GEAR);
optionsButton.addActionListener(e -> this.frame.showOptions());

@@ -117,10 +123,17 @@ public class PlayView extends JPanel {
profilesLabel.setForeground(new Color(160, 160, 160));
profilesLabel.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 0));

JPanel left = new JPanel(new MigLayout("fill, insets 0", "[fill]", "[]4[]0[]12[]12[]0[]"));
FlatButton refreshButton = new FlatButton("Refresh", LauncherFonts.OPEN_SANS_REGULAR.deriveFont(12.0f));
refreshButton.setStyle(FlatButton.ButtonStyle.TRANSPARENT);
refreshButton.setAlign(FlatButton.AlignState.LEFT);
refreshButton.setButtonIcon(LauncherIcons.REFRESH);
refreshButton.addActionListener(e -> this.refresh());

JPanel left = new JPanel(new MigLayout("fill, insets 0", "[fill]", "[]4[]0[]12[]8[]12[]0[]0"));
left.add(this.userIndicator, "wrap");
left.add(this.switchUserButton, "wrap");
left.add(optionsButton, "wrap");
left.add(refreshButton, "wrap");
left.add(profilesLabel, "wrap");
left.add(this.instancesTable, "grow, push, wrap");
left.add(this.launchButton, "wrap");
@@ -164,25 +177,8 @@ public class PlayView extends JPanel {
newsLayout.setHgap(7);
newsLayout.setVgap(7);

JPanel news = new JPanel(newsLayout);
news.setOpaque(false);

this.frame.getNewsFeedManager().refresh(value -> SwingUtilities.invokeLater(() -> {
news.removeAll();

int i= 0;

for (NewsFeedManager.NewsDataElement e : value.getNews()) {
NewsElement element = new NewsElement(this.frame.getNewsFeedManager(), e, i > 1);

news.add(element);

i++;
}

news.revalidate();
news.repaint();
}), true);
this.news = new JPanel(newsLayout);
this.news.setOpaque(false);

right.add(news, BorderLayout.CENTER);

@@ -190,6 +186,10 @@ public class PlayView extends JPanel {

right.add(this.progressIndicatorPanel, BorderLayout.SOUTH);

this.bannerPanel = new BannerPanel();

right.add(this.bannerPanel, BorderLayout.NORTH);

JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, left, right);
splitPane.setResizeWeight(0.0D);
splitPane.setDividerLocation(250);
@@ -239,6 +239,25 @@ public class PlayView extends JPanel {
});
}

private void layoutNewsTiles(NewsFeedManager.NewsFeed feed) {
SwingUtilities.invokeLater(() -> {
this.news.removeAll();

int i= 0;

for (NewsFeedManager.NewsDataElement e : feed.getNews()) {
NewsElement element = new NewsElement(this.frame.getNewsFeedManager(), e, i > 1);

this.news.add(element);

i++;
}

this.news.revalidate();
this.news.repaint();
});
}

public void updateUserIndicator(Account account) {
this.userIndicator.setAccount(account);
}
@@ -304,7 +323,7 @@ public class PlayView extends JPanel {
}

menuItem = new JMenuItem(SharedLocale.tr("launcher.refreshList"));
menuItem.addActionListener(e -> this.loadInstances());
menuItem.addActionListener(e -> this.refresh());
popup.add(menuItem);

popup.show(component, x, y);
@@ -318,7 +337,7 @@ public class PlayView extends JPanel {
ObservableFuture<Instance> future = this.launcher.getInstanceTasks().delete(this.frame, instance);

// Update the list of instances after updating
future.addListener(this::loadInstances, SwingExecutor.INSTANCE);
future.addListener(this::refresh, SwingExecutor.INSTANCE);
}

private void confirmHardUpdate(Instance instance) {
@@ -335,21 +354,53 @@ public class PlayView extends JPanel {
}, SwingExecutor.INSTANCE);
}

private void loadInstances() {
ObservableFuture<InstanceList> future = this.launcher.getInstanceTasks().reloadInstances();
private void refresh() {
ObservableFuture<InstanceList> refreshInstancesFuture = this.launcher.getInstanceTasks().reloadInstances();

ProgressView progressView = new ProgressView(this.frame, future, future, "Checking for updates");
this.frame.getLauncherLayout().show(progressView);
this.bannerPanel.update(LauncherIcons.REFRESH, "Checking for the latest updates", BannerPanel.BannerType.INFO);

future.addListener(() -> {
Futures.addCallback(refreshInstancesFuture, new FutureCallback<InstanceList>() {
@Override
public void onSuccess(@Nullable InstanceList result) {
PlayView.this.bannerPanel.close();
}

@Override
public void onFailure(Throwable t) {
PlayView.this.bannerPanel.update(LauncherIcons.WARN, "There was a problem checking for updates.", BannerPanel.BannerType.ERROR);
PlayView.this.bannerPanel.bindActionHandler(LauncherIcons.REFRESH, "Refresh", PlayView.this::refresh);
}
});

refreshInstancesFuture.addListener(() -> {
this.instancesModel.update();

if (this.instancesTable.getRowCount() > 0) {
this.instancesTable.setRowSelectionInterval(0, 0);
}

this.requestFocus();

this.refreshNews();
}, SwingExecutor.INSTANCE);

SwingHelper.addErrorDialogCallback(this.frame, future);
// SwingHelper.addErrorDialogCallback(this.frame, refreshInstancesFuture);
}

private void refreshNews() {
ListenableFuture<NewsFeedManager.NewsFeed> refreshNewsFuture = this.frame.getNewsFeedManager().refresh(false);

Futures.addCallback(refreshNewsFuture, new FutureCallback<NewsFeedManager.NewsFeed>() {
@Override
public void onSuccess(@Nullable NewsFeedManager.NewsFeed result) {
PlayView.this.layoutNewsTiles(result);
}

@Override
public void onFailure(Throwable t) {

}
});
}

private void launch() {

launcher-aether/src/main/resources/com/gildedgames/assets/icons/add.png → launcher-aether/src/main/resources/com/gildedgames/assets/icons/16/add.png View File


launcher-aether/src/main/resources/com/gildedgames/assets/icons/bug.png → launcher-aether/src/main/resources/com/gildedgames/assets/icons/16/bug.png View File


launcher-aether/src/main/resources/com/gildedgames/assets/icons/close.png → launcher-aether/src/main/resources/com/gildedgames/assets/icons/16/close.png View File


launcher-aether/src/main/resources/com/gildedgames/assets/icons/gear.png → launcher-aether/src/main/resources/com/gildedgames/assets/icons/16/gear.png View File


launcher-aether/src/main/resources/com/gildedgames/assets/icons/maximize.png → launcher-aether/src/main/resources/com/gildedgames/assets/icons/16/maximize.png View File


launcher-aether/src/main/resources/com/gildedgames/assets/icons/minimize.png → launcher-aether/src/main/resources/com/gildedgames/assets/icons/16/minimize.png View File


launcher-aether/src/main/resources/com/gildedgames/assets/icons/play.png → launcher-aether/src/main/resources/com/gildedgames/assets/icons/16/play.png View File


launcher-aether/src/main/resources/com/gildedgames/assets/icons/refresh.png → launcher-aether/src/main/resources/com/gildedgames/assets/icons/16/refresh.png View File


launcher-aether/src/main/resources/com/gildedgames/assets/icons/remove.png → launcher-aether/src/main/resources/com/gildedgames/assets/icons/16/remove.png View File


launcher-aether/src/main/resources/com/gildedgames/assets/icons/switch_user.png → launcher-aether/src/main/resources/com/gildedgames/assets/icons/16/switch_user.png View File


BIN
launcher-aether/src/main/resources/com/gildedgames/assets/icons/16/warn.png View File


BIN
launcher-aether/src/main/resources/com/gildedgames/assets/icons/64/warn.png View File


+ 0
- 2
launcher-fancy/accounts.dat View File

@@ -1,2 +0,0 @@
{Ê^ÌÐà÷ô~E‚g3U�ßùO}Òj®Éç�»ýPG —^2�ÈOÑ“`XóÚÑÏ1Mç]³wï©QeåE£ Ü“TAÓ÷Bщ°ÂÝc™38tn9E±Væò½X^æb
èm—¼ÉˆEù›[

+ 0
- 1
launcher-fancy/config.json View File

@@ -1 +0,0 @@
{"offlineEnabled":true,"jvmPath":null,"jvmArgs":null,"minMemory":1024,"maxMemory":4096,"permGen":256,"windowWidth":854,"widowHeight":480,"proxyEnabled":false,"proxyHost":"localhost","proxyPort":8080,"proxyUsername":null,"proxyPassword":null,"gameKey":null}

+ 4
- 5
launcher/src/main/java/com/skcraft/concurrency/ObservableFuture.java View File

@@ -9,10 +9,7 @@ package com.skcraft.concurrency;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.NonNull;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.*;

/**
* A pair of ProgressObservable and ListenableFuture.
@@ -35,7 +32,9 @@ public class ObservableFuture<V> implements ListenableFuture<V>, ProgressObserva
this.observable = observable;
}

@Override


@Override
public boolean cancel(boolean mayInterruptIfRunning) {
return future.cancel(mayInterruptIfRunning);
}

Loading…
Cancel
Save