fix: main page account item not working properly

This commit is contained in:
Haowei Wen 2021-08-27 22:57:49 +08:00
parent 6ac3f68dfc
commit a85d3b504f
No known key found for this signature in database
GPG Key ID: 5BC167F73EA558E4
4 changed files with 67 additions and 41 deletions

View File

@ -1,6 +1,6 @@
/* /*
* Hello Minecraft! Launcher * Hello Minecraft! Launcher
* Copyright (C) 2020 huangyuhui <huanghongxun2008@126.com> and contributors * Copyright (C) 2021 huangyuhui <huanghongxun2008@126.com> and contributors
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -20,14 +20,13 @@ package org.jackhuang.hmcl.game;
import javafx.beans.binding.Bindings; import javafx.beans.binding.Bindings;
import javafx.beans.binding.ObjectBinding; import javafx.beans.binding.ObjectBinding;
import javafx.scene.image.Image; import javafx.scene.image.Image;
import javafx.scene.image.PixelWriter;
import javafx.scene.image.WritableImage;
import org.jackhuang.hmcl.Metadata; import org.jackhuang.hmcl.Metadata;
import org.jackhuang.hmcl.auth.Account; import org.jackhuang.hmcl.auth.Account;
import org.jackhuang.hmcl.auth.ServerResponseMalformedException; import org.jackhuang.hmcl.auth.ServerResponseMalformedException;
import org.jackhuang.hmcl.auth.microsoft.MicrosoftAccount; import org.jackhuang.hmcl.auth.microsoft.MicrosoftAccount;
import org.jackhuang.hmcl.auth.yggdrasil.*; import org.jackhuang.hmcl.auth.yggdrasil.*;
import org.jackhuang.hmcl.task.FileDownloadTask; import org.jackhuang.hmcl.task.FileDownloadTask;
import org.jackhuang.hmcl.ui.FXUtils;
import org.jackhuang.hmcl.util.ResourceNotFoundError; import org.jackhuang.hmcl.util.ResourceNotFoundError;
import org.jackhuang.hmcl.util.StringUtils; import org.jackhuang.hmcl.util.StringUtils;
import org.jackhuang.hmcl.util.javafx.BindingMapping; import org.jackhuang.hmcl.util.javafx.BindingMapping;
@ -231,34 +230,18 @@ public final class TexturesLoader {
public static ObjectBinding<Image> fxAvatarBinding(YggdrasilService service, UUID uuid, int size) { public static ObjectBinding<Image> fxAvatarBinding(YggdrasilService service, UUID uuid, int size) {
return BindingMapping.of(skinBinding(service, uuid)) return BindingMapping.of(skinBinding(service, uuid))
.map(it -> toAvatar(it.image, size)) .map(it -> toAvatar(it.image, size))
.map(TexturesLoader::toFXImage); .map(FXUtils::toFXImage);
} }
public static ObjectBinding<Image> fxAvatarBinding(Account account, int size) { public static ObjectBinding<Image> fxAvatarBinding(Account account, int size) {
if (account instanceof YggdrasilAccount || account instanceof MicrosoftAccount) { if (account instanceof YggdrasilAccount || account instanceof MicrosoftAccount) {
return BindingMapping.of(skinBinding(account)) return BindingMapping.of(skinBinding(account))
.map(it -> toAvatar(it.image, size)) .map(it -> toAvatar(it.image, size))
.map(TexturesLoader::toFXImage); .map(FXUtils::toFXImage);
} else { } else {
return Bindings.createObjectBinding( return Bindings.createObjectBinding(
() -> toFXImage(toAvatar(getDefaultSkin(TextureModel.detectUUID(account.getUUID())).image, size))); () -> FXUtils.toFXImage(toAvatar(getDefaultSkin(TextureModel.detectUUID(account.getUUID())).image, size)));
} }
} }
// ==== // ====
// Based on https://stackoverflow.com/a/57552025
// Fix #874: Use it instead of SwingFXUtils.toFXImage
private static WritableImage toFXImage(BufferedImage image) {
WritableImage wr = new WritableImage(image.getWidth(), image.getHeight());
PixelWriter pw = wr.getPixelWriter();
final int iw = image.getWidth();
final int ih = image.getHeight();
for (int x = 0; x < iw; x++) {
for (int y = 0; y < ih; y++) {
pw.setArgb(x, y, image.getRGB(x, y));
}
}
return wr;
}
} }

View File

@ -38,6 +38,8 @@ import javafx.scene.Node;
import javafx.scene.control.*; import javafx.scene.control.*;
import javafx.scene.image.Image; import javafx.scene.image.Image;
import javafx.scene.image.ImageView; import javafx.scene.image.ImageView;
import javafx.scene.image.PixelWriter;
import javafx.scene.image.WritableImage;
import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent; import javafx.scene.input.KeyEvent;
import javafx.scene.input.TransferMode; import javafx.scene.input.TransferMode;
@ -55,6 +57,7 @@ import org.jackhuang.hmcl.util.javafx.ExtendedProperties;
import org.jackhuang.hmcl.util.javafx.SafeStringConverter; import org.jackhuang.hmcl.util.javafx.SafeStringConverter;
import org.jackhuang.hmcl.util.platform.OperatingSystem; import org.jackhuang.hmcl.util.platform.OperatingSystem;
import java.awt.image.BufferedImage;
import java.io.File; import java.io.File;
import java.io.FileFilter; import java.io.FileFilter;
import java.io.IOException; import java.io.IOException;
@ -552,4 +555,20 @@ public final class FXUtils {
} }
}); });
} }
// Based on https://stackoverflow.com/a/57552025
// Fix #874: Use it instead of SwingFXUtils.toFXImage
public static WritableImage toFXImage(BufferedImage image) {
WritableImage wr = new WritableImage(image.getWidth(), image.getHeight());
PixelWriter pw = wr.getPixelWriter();
final int iw = image.getWidth();
final int ih = image.getHeight();
for (int x = 0; x < iw; x++) {
for (int y = 0; y < ih; y++) {
pw.setArgb(x, y, image.getRGB(x, y));
}
}
return wr;
}
} }

View File

@ -1,6 +1,6 @@
/* /*
* Hello Minecraft! Launcher * Hello Minecraft! Launcher
* Copyright (C) 2020 huangyuhui <huanghongxun2008@126.com> and contributors * Copyright (C) 2021 huangyuhui <huanghongxun2008@126.com> and contributors
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -20,6 +20,7 @@ package org.jackhuang.hmcl.ui.account;
import javafx.beans.binding.Bindings; import javafx.beans.binding.Bindings;
import javafx.beans.property.ObjectProperty; import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
import javafx.scene.Node; import javafx.scene.Node;
import javafx.scene.control.Tooltip; import javafx.scene.control.Tooltip;
@ -27,14 +28,19 @@ import javafx.scene.image.ImageView;
import org.jackhuang.hmcl.auth.Account; import org.jackhuang.hmcl.auth.Account;
import org.jackhuang.hmcl.auth.authlibinjector.AuthlibInjectorAccount; import org.jackhuang.hmcl.auth.authlibinjector.AuthlibInjectorAccount;
import org.jackhuang.hmcl.auth.authlibinjector.AuthlibInjectorServer; import org.jackhuang.hmcl.auth.authlibinjector.AuthlibInjectorServer;
import org.jackhuang.hmcl.auth.yggdrasil.TextureModel;
import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilAccount; import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilAccount;
import org.jackhuang.hmcl.game.TexturesLoader; import org.jackhuang.hmcl.game.TexturesLoader;
import org.jackhuang.hmcl.setting.Accounts; import org.jackhuang.hmcl.setting.Accounts;
import org.jackhuang.hmcl.ui.FXUtils; import org.jackhuang.hmcl.ui.FXUtils;
import org.jackhuang.hmcl.ui.construct.AdvancedListItem; import org.jackhuang.hmcl.ui.construct.AdvancedListItem;
import org.jackhuang.hmcl.util.Pair; import org.jackhuang.hmcl.util.Pair;
import org.jackhuang.hmcl.util.javafx.BindingMapping;
import static org.jackhuang.hmcl.ui.FXUtils.newImage; import static javafx.beans.binding.Bindings.createStringBinding;
import static org.jackhuang.hmcl.setting.Accounts.getAccountFactory;
import static org.jackhuang.hmcl.setting.Accounts.getLocalizedLoginTypeName;
import static org.jackhuang.hmcl.ui.FXUtils.toFXImage;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n; import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public class AccountAdvancedListItem extends AdvancedListItem { public class AccountAdvancedListItem extends AdvancedListItem {
@ -48,16 +54,18 @@ public class AccountAdvancedListItem extends AdvancedListItem {
Account account = get(); Account account = get();
if (account == null) { if (account == null) {
titleProperty().unbind(); titleProperty().unbind();
subtitleProperty().unbind();
imageView.imageProperty().unbind();
tooltip.textProperty().unbind();
setTitle(i18n("account.missing")); setTitle(i18n("account.missing"));
setSubtitle(i18n("account.missing.add")); setSubtitle(i18n("account.missing.add"));
imageView.imageProperty().unbind(); imageView.setImage(toFXImage(TexturesLoader.toAvatar(TexturesLoader.getDefaultSkin(TextureModel.STEVE).getImage(), 32)));
imageView.setImage(newImage("/assets/img/steve.png")); tooltip.setText(i18n("account.create"));
tooltip.setText("");
} else { } else {
titleProperty().bind(Bindings.createStringBinding(account::getCharacter, account)); titleProperty().bind(BindingMapping.of(account, Account::getCharacter));
setSubtitle(accountSubtitle(account)); subtitleProperty().bind(accountSubtitle(account));
imageView.imageProperty().bind(TexturesLoader.fxAvatarBinding(account, 32)); imageView.imageProperty().bind(TexturesLoader.fxAvatarBinding(account, 32));
tooltip.setText(account.getCharacter() + " " + accountTooltip(account)); tooltip.textProperty().bind(accountTooltip(account));
} }
} }
}; };
@ -88,23 +96,27 @@ public class AccountAdvancedListItem extends AdvancedListItem {
return account; return account;
} }
private static String accountSubtitle(Account account) { private static ObservableValue<String> accountSubtitle(Account account) {
String loginTypeName = Accounts.getLocalizedLoginTypeName(Accounts.getAccountFactory(account));
if (account instanceof AuthlibInjectorAccount) { if (account instanceof AuthlibInjectorAccount) {
return ((AuthlibInjectorAccount) account).getServer().getName(); return BindingMapping.of(((AuthlibInjectorAccount) account).getServer(), AuthlibInjectorServer::getName);
} else { } else {
return loginTypeName; return createStringBinding(() -> getLocalizedLoginTypeName(getAccountFactory(account)));
} }
} }
private static String accountTooltip(Account account) { private static ObservableValue<String> accountTooltip(Account account) {
if (account instanceof AuthlibInjectorAccount) { if (account instanceof AuthlibInjectorAccount) {
AuthlibInjectorServer server = ((AuthlibInjectorAccount) account).getServer(); AuthlibInjectorServer server = ((AuthlibInjectorAccount) account).getServer();
return account.getUsername() + ", " + i18n("account.injector.server") + ": " + server.getName(); return Bindings.format("%s (%s) (%s)",
BindingMapping.of(account, Account::getCharacter),
account.getUsername(),
BindingMapping.of(server, AuthlibInjectorServer::getName));
} else if (account instanceof YggdrasilAccount) { } else if (account instanceof YggdrasilAccount) {
return account.getUsername(); return Bindings.format("%s (%s)",
BindingMapping.of(account, Account::getCharacter),
account.getUsername());
} else { } else {
return ""; return BindingMapping.of(account, Account::getCharacter);
} }
} }

View File

@ -1,6 +1,6 @@
/* /*
* Hello Minecraft! Launcher * Hello Minecraft! Launcher
* Copyright (C) 2020 huangyuhui <huanghongxun2008@126.com> and contributors * Copyright (C) 2021 huangyuhui <huanghongxun2008@126.com> and contributors
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -157,11 +157,16 @@ public class RootPage extends DecoratorTabPage {
return accountTab; return accountTab;
} }
private void selectPage(Tab tab) { /**
* @return true if the tab is being opened, or false if the tab is being closed
*/
private boolean selectPage(Tab tab) {
if (getSelectionModel().getSelectedItem() == tab) { if (getSelectionModel().getSelectedItem() == tab) {
getSelectionModel().select(getMainTab()); getSelectionModel().select(getMainTab());
return false;
} else { } else {
getSelectionModel().select(tab); getSelectionModel().select(tab);
return true;
} }
} }
@ -173,7 +178,14 @@ public class RootPage extends DecoratorTabPage {
// first item in left sidebar // first item in left sidebar
AccountAdvancedListItem accountListItem = new AccountAdvancedListItem(); AccountAdvancedListItem accountListItem = new AccountAdvancedListItem();
accountListItem.activeProperty().bind(control.accountTab.selectedProperty()); accountListItem.activeProperty().bind(control.accountTab.selectedProperty());
accountListItem.setOnAction(e -> control.selectPage(control.accountTab)); accountListItem.setOnAction(e -> {
if (control.selectPage(control.accountTab)) {
// open create account dialog if no account exists
if (Accounts.getAccounts().isEmpty()) {
Controllers.dialog(new AddAccountPane());
}
}
});
accountListItem.accountProperty().bind(Accounts.selectedAccountProperty()); accountListItem.accountProperty().bind(Accounts.selectedAccountProperty());
// second item in left sidebar // second item in left sidebar