GUI, preferences: added theme switch without app restart (for preview only, app must be restarted anyway for full GUI refresh);

This commit is contained in:
Oleg Agafonov 2024-07-03 04:31:07 +04:00
parent e3dee4eac1
commit 64f3df035b
10 changed files with 234 additions and 135 deletions

View file

@ -31,6 +31,7 @@ import mage.client.tournament.TournamentPane;
import mage.client.util.*; import mage.client.util.*;
import mage.client.util.audio.MusicPlayer; import mage.client.util.audio.MusicPlayer;
import mage.client.util.gui.ArrowBuilder; import mage.client.util.gui.ArrowBuilder;
import mage.client.util.gui.GuiDisplayUtil;
import mage.client.util.gui.countryBox.CountryUtil; import mage.client.util.gui.countryBox.CountryUtil;
import mage.client.util.sets.ConstructedFormats; import mage.client.util.sets.ConstructedFormats;
import mage.client.util.stats.UpdateMemUsageTask; import mage.client.util.stats.UpdateMemUsageTask;
@ -229,33 +230,17 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
config.setArchiveDetector(new TArchiveDetector("zip")); config.setArchiveDetector(new TArchiveDetector("zip"));
config.setAccessPreference(FsAccessOption.STORE, true); config.setAccessPreference(FsAccessOption.STORE, true);
try { // apply current theme
UIManager.put("desktop", new Color(0, 0, 0, 0)); GUISizeHelper.calculateGUISizes();
UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel"); GuiDisplayUtil.refreshThemeSettings();
UIManager.put("nimbusBlueGrey", PreferencesDialog.getCurrentTheme().getNimbusBlueGrey()); // buttons, scrollbar background, disabled inputs // workaround to stop JSplitPane from eating F6 and F8 or any other function keys
UIManager.put("control", PreferencesDialog.getCurrentTheme().getControl()); // window bg Object value = UIManager.get("SplitPane.ancestorInputMap");
UIManager.put("nimbusLightBackground", PreferencesDialog.getCurrentTheme().getNimbusLightBackground()); // inputs, table rows if (value instanceof InputMap) {
UIManager.put("info", PreferencesDialog.getCurrentTheme().getInfo()); // tooltips InputMap map = (InputMap) value;
UIManager.put("nimbusBase", PreferencesDialog.getCurrentTheme().getNimbusBase()); // title bars, scrollbar foreground for (int vk = KeyEvent.VK_F2; vk <= KeyEvent.VK_F12; ++vk) {
map.remove(KeyStroke.getKeyStroke(vk, 0));
//UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
// stop JSplitPane from eating F6 and F8 or any other function keys
{
Object value = UIManager.get("SplitPane.ancestorInputMap");
if (value instanceof InputMap) {
InputMap map = (InputMap) value;
for (int vk = KeyEvent.VK_F2; vk <= KeyEvent.VK_F12; ++vk) {
map.remove(KeyStroke.getKeyStroke(vk, 0));
}
}
} }
GUISizeHelper.calculateGUISizes();
// UIManager.put("Table.rowHeight", GUISizeHelper.tableRowHeight);
} catch (Exception ex) {
LOGGER.fatal(null, ex);
} }
// other settings // other settings
@ -1529,7 +1514,7 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
// Needed to layout the tooltbar after text length change // Needed to layout the tooltbar after text length change
// TODO: need research, is it actual? // TODO: need research, is it actual?
GUISizeHelper.refreshGUIAndCards(); GUISizeHelper.refreshGUIAndCards(false);
this.btnConnect.repaint(); this.btnConnect.repaint();
this.btnConnect.revalidate(); this.btnConnect.revalidate();

View file

@ -6142,8 +6142,8 @@
<Container class="javax.swing.JPanel" name="tabThemes"> <Container class="javax.swing.JPanel" name="tabThemes">
<Constraints> <Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout$JTabbedPaneConstraintsDescription"> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout$JTabbedPaneConstraintsDescription">
<JTabbedPaneConstraints tabName="Themes"> <JTabbedPaneConstraints tabName="GUI theme">
<Property name="tabTitle" type="java.lang.String" value="Themes"/> <Property name="tabTitle" type="java.lang.String" value="GUI theme"/>
</JTabbedPaneConstraints> </JTabbedPaneConstraints>
</Constraint> </Constraint>
</Constraints> </Constraints>
@ -6151,25 +6151,19 @@
<Layout> <Layout>
<DimensionLayout dim="0"> <DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="807" max="32767" attributes="0"/> <Group type="102" alignment="1" attributes="0">
<Group type="103" rootIndex="1" groupAlignment="0" attributes="0"> <EmptySpace max="-2" attributes="0"/>
<Group type="102" alignment="0" attributes="0"> <Component id="themesCategory" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Component id="themesCategory" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group> </Group>
</Group> </Group>
</DimensionLayout> </DimensionLayout>
<DimensionLayout dim="1"> <DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="556" max="32767" attributes="0"/> <Group type="102" alignment="0" attributes="0">
<Group type="103" rootIndex="1" groupAlignment="0" attributes="0"> <EmptySpace max="-2" attributes="0"/>
<Group type="102" alignment="0" attributes="0"> <Component id="themesCategory" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="21" max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Component id="themesCategory" min="-2" max="-2" attributes="0"/>
<EmptySpace pref="460" max="32767" attributes="0"/>
</Group>
</Group> </Group>
</Group> </Group>
</DimensionLayout> </DimensionLayout>
@ -6194,25 +6188,25 @@
<Group type="102" alignment="0" attributes="0"> <Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Component id="lbSelectLabel" min="-2" pref="96" max="-2" attributes="0"/> <Component id="lbSelectLabel" min="-2" pref="96" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/> <EmptySpace type="unrelated" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Component id="lbThemeHint" min="-2" max="-2" attributes="0"/> <Component id="lbThemeHint" min="-2" max="-2" attributes="0"/>
<Component id="cbTheme" min="-2" pref="303" max="-2" attributes="0"/> <Component id="cbTheme" min="-2" pref="313" max="-2" attributes="0"/>
</Group> </Group>
<EmptySpace pref="360" max="32767" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
</Group> </Group>
</Group> </Group>
</DimensionLayout> </DimensionLayout>
<DimensionLayout dim="1"> <DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0"> <Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="1" attributes="0"> <Group type="103" groupAlignment="1" attributes="0">
<Component id="cbTheme" min="-2" max="-2" attributes="0"/> <Component id="cbTheme" min="-2" max="-2" attributes="0"/>
<Component id="lbSelectLabel" min="-2" pref="22" max="-2" attributes="0"/> <Component id="lbSelectLabel" min="-2" pref="22" max="-2" attributes="0"/>
</Group> </Group>
<EmptySpace max="-2" attributes="0"/> <EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="lbThemeHint" min="-2" max="-2" attributes="0"/> <Component id="lbThemeHint" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
</Group> </Group>
</Group> </Group>
</DimensionLayout> </DimensionLayout>
@ -6221,7 +6215,7 @@
<Component class="javax.swing.JLabel" name="lbSelectLabel"> <Component class="javax.swing.JLabel" name="lbSelectLabel">
<Properties> <Properties>
<Property name="horizontalAlignment" type="int" value="2"/> <Property name="horizontalAlignment" type="int" value="2"/>
<Property name="text" type="java.lang.String" value="Select a theme:"/> <Property name="text" type="java.lang.String" value="Color style:"/>
<Property name="toolTipText" type="java.lang.String" value=""/> <Property name="toolTipText" type="java.lang.String" value=""/>
<Property name="horizontalTextPosition" type="int" value="10"/> <Property name="horizontalTextPosition" type="int" value="10"/>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor"> <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
@ -6231,13 +6225,16 @@
</Properties> </Properties>
</Component> </Component>
<Component class="javax.swing.JComboBox" name="cbTheme"> <Component class="javax.swing.JComboBox" name="cbTheme">
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cbThemeActionPerformed"/>
</Events>
<AuxValues> <AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;ThemeType&gt;"/> <AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;ThemeType&gt;"/>
</AuxValues> </AuxValues>
</Component> </Component>
<Component class="javax.swing.JLabel" name="lbThemeHint"> <Component class="javax.swing.JLabel" name="lbThemeHint">
<Properties> <Properties>
<Property name="text" type="java.lang.String" value="Requires a restart to apply new theme."/> <Property name="text" type="java.lang.String" value="WARNING, some color settings will be applied after app RESTART"/>
</Properties> </Properties>
</Component> </Component>
</SubComponents> </SubComponents>

View file

@ -344,26 +344,36 @@ public class PreferencesDialog extends javax.swing.JDialog {
private static ThemeType currentTheme = null; private static ThemeType currentTheme = null;
private static boolean ignoreGUISizeSliderStateChangedEvent = false; // prevent fast settings apply on form loading
private static boolean isLoadingSizes = false;
private static boolean isLoadingTheme = false;
public static ThemeType getCurrentTheme() { public static ThemeType getCurrentTheme() {
if (currentTheme == null) { if (currentTheme == null) {
currentTheme = ThemeType.valueByName(getCachedValue(KEY_THEME, "Default")); // first init
logger.info("Using GUI theme: " + currentTheme.getName()); loadTheme();
currentTheme.reload();
} }
return currentTheme; return currentTheme;
} }
private static void loadTheme() {
currentTheme = ThemeType.valueByName(getCachedValue(KEY_THEME, "Default"));
logger.info("Using GUI theme: " + currentTheme.getName());
currentTheme.reload();
}
/** /**
* Set and reload current theme. App need restart to apply all new settings. * Set and reload current theme. App need restart to apply all new settings.
* *
* @param newTheme * @param newTheme
*/ */
public static void setCurrentTheme(ThemeType newTheme) { public static void setCurrentTheme(ThemeType newTheme) {
boolean needReload = currentTheme != newTheme;
currentTheme = newTheme; currentTheme = newTheme;
currentTheme.reload(); if (needReload) {
currentTheme.reload();
}
} }
private final JFileChooser fc = new JFileChooser(); private final JFileChooser fc = new JFileChooser();
@ -2603,13 +2613,19 @@ public class PreferencesDialog extends javax.swing.JDialog {
themesCategory.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createEtchedBorder(), "Themes")); themesCategory.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createEtchedBorder(), "Themes"));
lbSelectLabel.setHorizontalAlignment(javax.swing.SwingConstants.LEFT); lbSelectLabel.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
lbSelectLabel.setText("Select a theme:"); lbSelectLabel.setText("Color style:");
lbSelectLabel.setToolTipText(""); lbSelectLabel.setToolTipText("");
lbSelectLabel.setHorizontalTextPosition(javax.swing.SwingConstants.LEADING); lbSelectLabel.setHorizontalTextPosition(javax.swing.SwingConstants.LEADING);
lbSelectLabel.setPreferredSize(new java.awt.Dimension(110, 16)); lbSelectLabel.setPreferredSize(new java.awt.Dimension(110, 16));
lbSelectLabel.setVerticalTextPosition(javax.swing.SwingConstants.TOP); lbSelectLabel.setVerticalTextPosition(javax.swing.SwingConstants.TOP);
lbThemeHint.setText("Requires a restart to apply new theme."); cbTheme.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
cbThemeActionPerformed(evt);
}
});
lbThemeHint.setText("WARNING, some color settings will be applied after app RESTART");
org.jdesktop.layout.GroupLayout themesCategoryLayout = new org.jdesktop.layout.GroupLayout(themesCategory); org.jdesktop.layout.GroupLayout themesCategoryLayout = new org.jdesktop.layout.GroupLayout(themesCategory);
themesCategory.setLayout(themesCategoryLayout); themesCategory.setLayout(themesCategoryLayout);
@ -2618,45 +2634,41 @@ public class PreferencesDialog extends javax.swing.JDialog {
.add(themesCategoryLayout.createSequentialGroup() .add(themesCategoryLayout.createSequentialGroup()
.addContainerGap() .addContainerGap()
.add(lbSelectLabel, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 96, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) .add(lbSelectLabel, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 96, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED)
.add(themesCategoryLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(themesCategoryLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
.add(lbThemeHint) .add(lbThemeHint)
.add(cbTheme, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 303, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) .add(cbTheme, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 313, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
.addContainerGap(360, Short.MAX_VALUE)) .addContainerGap())
); );
themesCategoryLayout.setVerticalGroup( themesCategoryLayout.setVerticalGroup(
themesCategoryLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) themesCategoryLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
.add(themesCategoryLayout.createSequentialGroup() .add(themesCategoryLayout.createSequentialGroup()
.addContainerGap()
.add(themesCategoryLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING) .add(themesCategoryLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING)
.add(cbTheme, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) .add(cbTheme, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
.add(lbSelectLabel, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 22, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) .add(lbSelectLabel, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 22, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED)
.add(lbThemeHint) .add(lbThemeHint))
.addContainerGap(org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
); );
org.jdesktop.layout.GroupLayout tabThemesLayout = new org.jdesktop.layout.GroupLayout(tabThemes); org.jdesktop.layout.GroupLayout tabThemesLayout = new org.jdesktop.layout.GroupLayout(tabThemes);
tabThemes.setLayout(tabThemesLayout); tabThemes.setLayout(tabThemesLayout);
tabThemesLayout.setHorizontalGroup( tabThemesLayout.setHorizontalGroup(
tabThemesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) tabThemesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
.add(0, 807, Short.MAX_VALUE) .add(org.jdesktop.layout.GroupLayout.TRAILING, tabThemesLayout.createSequentialGroup()
.add(tabThemesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .addContainerGap()
.add(tabThemesLayout.createSequentialGroup() .add(themesCategory, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addContainerGap() .addContainerGap())
.add(themesCategory, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addContainerGap()))
); );
tabThemesLayout.setVerticalGroup( tabThemesLayout.setVerticalGroup(
tabThemesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) tabThemesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
.add(0, 556, Short.MAX_VALUE) .add(tabThemesLayout.createSequentialGroup()
.add(tabThemesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .addContainerGap()
.add(tabThemesLayout.createSequentialGroup() .add(themesCategory, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
.add(21, 21, 21) .addContainerGap())
.add(themesCategory, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
.addContainerGap(460, Short.MAX_VALUE)))
); );
tabsPanel.addTab("Themes", tabThemes); tabsPanel.addTab("GUI theme", tabThemes);
saveButton.setLabel("Save"); saveButton.setLabel("Save");
saveButton.setMaximumSize(new java.awt.Dimension(100, 30)); saveButton.setMaximumSize(new java.awt.Dimension(100, 30));
@ -2747,7 +2759,7 @@ public class PreferencesDialog extends javax.swing.JDialog {
} }
} }
saveGUISize(); saveGUISize(false, false);
// Phases & Priority // Phases & Priority
save(prefs, dialog.checkBoxUpkeepYou, UPKEEP_YOU); save(prefs, dialog.checkBoxUpkeepYou, UPKEEP_YOU);
@ -2811,7 +2823,7 @@ public class PreferencesDialog extends javax.swing.JDialog {
MusicPlayer.stopBGM(); MusicPlayer.stopBGM();
} }
// connection // proxy
save(prefs, dialog.cbProxyType, KEY_PROXY_TYPE); save(prefs, dialog.cbProxyType, KEY_PROXY_TYPE);
save(prefs, dialog.txtProxyServer, KEY_PROXY_ADDRESS); save(prefs, dialog.txtProxyServer, KEY_PROXY_ADDRESS);
save(prefs, dialog.txtProxyPort, KEY_PROXY_PORT); save(prefs, dialog.txtProxyPort, KEY_PROXY_PORT);
@ -2836,7 +2848,7 @@ public class PreferencesDialog extends javax.swing.JDialog {
save(prefs, dialog.keySwitchChat); save(prefs, dialog.keySwitchChat);
// Themes // Themes
save(prefs, dialog.cbTheme, KEY_THEME); saveTheme(false);
// Avatar // Avatar
if (selectedAvatarId < MIN_AVATAR_ID || selectedAvatarId > MAX_AVATAR_ID) { if (selectedAvatarId < MIN_AVATAR_ID || selectedAvatarId > MAX_AVATAR_ID) {
@ -2845,6 +2857,10 @@ public class PreferencesDialog extends javax.swing.JDialog {
prefs.put(KEY_AVATAR, String.valueOf(selectedAvatarId)); prefs.put(KEY_AVATAR, String.valueOf(selectedAvatarId));
updateCache(KEY_AVATAR, String.valueOf(selectedAvatarId)); updateCache(KEY_AVATAR, String.valueOf(selectedAvatarId));
// refresh full GUI
GUISizeHelper.refreshGUIAndCards(true);
// send server side settings
try { try {
SessionHandler.updatePreferencesForServer(getUserData()); SessionHandler.updatePreferencesForServer(getUserData());
prefs.flush(); prefs.flush();
@ -2858,7 +2874,16 @@ public class PreferencesDialog extends javax.swing.JDialog {
dialog.setVisible(false); dialog.setVisible(false);
}//GEN-LAST:event_saveButtonActionPerformed }//GEN-LAST:event_saveButtonActionPerformed
private void saveGUISize() { private void saveTheme(boolean refreshTheme) {
Preferences prefs = MageFrame.getPreferences();
save(prefs, dialog.cbTheme, KEY_THEME);
if (refreshTheme) {
loadTheme();
}
}
private void saveGUISize(boolean refreshGUI, boolean refreshTheme) {
Preferences prefs = MageFrame.getPreferences(); Preferences prefs = MageFrame.getPreferences();
// GUI Size // GUI Size
@ -2876,8 +2901,10 @@ public class PreferencesDialog extends javax.swing.JDialog {
save(prefs, dialog.sliderCardSizeMinBattlefield, KEY_GUI_CARD_BATTLEFIELD_MIN_SIZE, "true", "false", UPDATE_CACHE_POLICY); save(prefs, dialog.sliderCardSizeMinBattlefield, KEY_GUI_CARD_BATTLEFIELD_MIN_SIZE, "true", "false", UPDATE_CACHE_POLICY);
save(prefs, dialog.sliderCardSizeMaxBattlefield, KEY_GUI_CARD_BATTLEFIELD_MAX_SIZE, "true", "false", UPDATE_CACHE_POLICY); save(prefs, dialog.sliderCardSizeMaxBattlefield, KEY_GUI_CARD_BATTLEFIELD_MAX_SIZE, "true", "false", UPDATE_CACHE_POLICY);
// refresh full GUI with new settings // refresh full GUI with new settings (except theme)
GUISizeHelper.refreshGUIAndCards(); if (refreshGUI) {
GUISizeHelper.refreshGUIAndCards(refreshTheme);
}
} }
private void exitButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_exitButtonActionPerformed private void exitButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_exitButtonActionPerformed
@ -3048,13 +3075,17 @@ public class PreferencesDialog extends javax.swing.JDialog {
}//GEN-LAST:event_cbUseDefaultImageFolderActionPerformed }//GEN-LAST:event_cbUseDefaultImageFolderActionPerformed
private void sliderGUISizeStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_sliderGUISizeStateChanged private void sliderGUISizeStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_sliderGUISizeStateChanged
// This prevents this event from firing during the initial if (!isLoadingSizes) {
// setting of the sliders from pref values saveGUISize(true, false); // do not refresh theme cause it heavy and stop active slider
if (!ignoreGUISizeSliderStateChangedEvent) {
saveGUISize();
} }
}//GEN-LAST:event_sliderGUISizeStateChanged }//GEN-LAST:event_sliderGUISizeStateChanged
private void cbThemeActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbThemeActionPerformed
if (!isLoadingTheme) {
saveTheme(true);
}
}//GEN-LAST:event_cbThemeActionPerformed
private void showProxySettings() { private void showProxySettings() {
Connection.ProxyType proxyType = (Connection.ProxyType) cbProxyType.getSelectedItem(); Connection.ProxyType proxyType = (Connection.ProxyType) cbProxyType.getSelectedItem();
switch (proxyType) { switch (proxyType) {
@ -3128,7 +3159,7 @@ public class PreferencesDialog extends javax.swing.JDialog {
// Sounds // Sounds
loadSoundSettings(prefs); loadSoundSettings(prefs);
// Connection // Proxy
loadProxySettings(prefs); loadProxySettings(prefs);
// Controls // Controls
@ -3221,21 +3252,24 @@ public class PreferencesDialog extends javax.swing.JDialog {
} }
private static void loadGuiSize(Preferences prefs) { private static void loadGuiSize(Preferences prefs) {
ignoreGUISizeSliderStateChangedEvent = true; isLoadingSizes = true;
load(prefs, dialog.sliderFontSize, KEY_GUI_TABLE_FONT_SIZE, "14"); try {
load(prefs, dialog.sliderChatFontSize, KEY_GUI_CHAT_FONT_SIZE, "14"); load(prefs, dialog.sliderFontSize, KEY_GUI_TABLE_FONT_SIZE, "14");
load(prefs, dialog.sliderCardSizeHand, KEY_GUI_CARD_HAND_SIZE, "14"); load(prefs, dialog.sliderChatFontSize, KEY_GUI_CHAT_FONT_SIZE, "14");
load(prefs, dialog.sliderEditorCardSize, KEY_GUI_CARD_EDITOR_SIZE, "14"); load(prefs, dialog.sliderCardSizeHand, KEY_GUI_CARD_HAND_SIZE, "14");
load(prefs, dialog.sliderEditorCardOffset, KEY_GUI_CARD_OFFSET_SIZE, "14"); load(prefs, dialog.sliderEditorCardSize, KEY_GUI_CARD_EDITOR_SIZE, "14");
load(prefs, dialog.sliderEnlargedImageSize, KEY_GUI_ENLARGED_IMAGE_SIZE, "20"); load(prefs, dialog.sliderEditorCardOffset, KEY_GUI_CARD_OFFSET_SIZE, "14");
load(prefs, dialog.sliderStackWidth, KEY_GUI_STACK_WIDTH, "14"); load(prefs, dialog.sliderEnlargedImageSize, KEY_GUI_ENLARGED_IMAGE_SIZE, "20");
load(prefs, dialog.sliderDialogFont, KEY_GUI_DIALOG_FONT_SIZE, "14"); load(prefs, dialog.sliderStackWidth, KEY_GUI_STACK_WIDTH, "14");
load(prefs, dialog.sliderTooltipSize, KEY_GUI_TOOLTIP_SIZE, "14"); load(prefs, dialog.sliderDialogFont, KEY_GUI_DIALOG_FONT_SIZE, "14");
load(prefs, dialog.sliderGameFeedbackArea, KEY_GUI_FEEDBACK_AREA_SIZE, "14"); load(prefs, dialog.sliderTooltipSize, KEY_GUI_TOOLTIP_SIZE, "14");
load(prefs, dialog.sliderCardSizeOtherZones, KEY_GUI_CARD_OTHER_ZONES_SIZE, "14"); load(prefs, dialog.sliderGameFeedbackArea, KEY_GUI_FEEDBACK_AREA_SIZE, "14");
load(prefs, dialog.sliderCardSizeMinBattlefield, KEY_GUI_CARD_BATTLEFIELD_MIN_SIZE, "10"); load(prefs, dialog.sliderCardSizeOtherZones, KEY_GUI_CARD_OTHER_ZONES_SIZE, "14");
load(prefs, dialog.sliderCardSizeMaxBattlefield, KEY_GUI_CARD_BATTLEFIELD_MAX_SIZE, "14"); load(prefs, dialog.sliderCardSizeMinBattlefield, KEY_GUI_CARD_BATTLEFIELD_MIN_SIZE, "10");
ignoreGUISizeSliderStateChangedEvent = false; load(prefs, dialog.sliderCardSizeMaxBattlefield, KEY_GUI_CARD_BATTLEFIELD_MAX_SIZE, "14");
} finally {
isLoadingSizes = false;
}
} }
private static void loadImagesSettings(Preferences prefs) { private static void loadImagesSettings(Preferences prefs) {
@ -3343,7 +3377,12 @@ public class PreferencesDialog extends javax.swing.JDialog {
} }
private static void loadThemeSettings(Preferences prefs) { private static void loadThemeSettings(Preferences prefs) {
dialog.cbTheme.setSelectedItem(PreferencesDialog.getCurrentTheme()); isLoadingTheme = true;
try {
dialog.cbTheme.setSelectedItem(PreferencesDialog.getCurrentTheme());
} finally {
isLoadingTheme = false;
}
} }
private static void loadSelectedAvatar(Preferences prefs) { private static void loadSelectedAvatar(Preferences prefs) {

View file

@ -65,6 +65,7 @@ import java.util.*;
public class TestCardRenderDialog extends MageDialog { public class TestCardRenderDialog extends MageDialog {
private static final Logger logger = Logger.getLogger(TestCardRenderDialog.class); private static final Logger logger = Logger.getLogger(TestCardRenderDialog.class);
float cardSizeMod = 1.0f; float cardSizeMod = 1.0f;
float playerSizeMod = 1.0f; float playerSizeMod = 1.0f;
private Match match = null; private Match match = null;
@ -108,7 +109,7 @@ public class TestCardRenderDialog extends MageDialog {
this.playerPanel.add(player, BorderLayout.CENTER); this.playerPanel.add(player, BorderLayout.CENTER);
// render cards // render cards
reloadCardsAndPlayer(); reloadCardsAndPlayer(false);
// windows settings // windows settings
MageFrame.getDesktop().remove(this); MageFrame.getDesktop().remove(this);
@ -260,9 +261,16 @@ public class TestCardRenderDialog extends MageDialog {
return cardView; return cardView;
} }
private void reloadCardsAndPlayer() { private void reloadCardsAndPlayer(boolean refreshTheme) {
// it contains GUI reload feature (must re-render all frames with new look and fill style),
// so call it for theme combobox only
// bug example: null errors on card size slider usage
// apply selected theme (warning, it will be applied for all app, so can be bugged in other dialogs - but it's ok for debug) // apply selected theme (warning, it will be applied for all app, so can be bugged in other dialogs - but it's ok for debug)
PreferencesDialog.setCurrentTheme((ThemeType) comboTheme.getSelectedItem()); // bug example: render part of elements with old colors
if (refreshTheme) {
PreferencesDialog.setCurrentTheme((ThemeType) comboTheme.getSelectedItem());
}
// prepare fake game and players without real match // prepare fake game and players without real match
// it's a workaround with minimum code and data init // it's a workaround with minimum code and data init
@ -868,13 +876,13 @@ public class TestCardRenderDialog extends MageDialog {
}//GEN-LAST:event_buttonCancelActionPerformed }//GEN-LAST:event_buttonCancelActionPerformed
private void buttonReloadCardsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonReloadCardsActionPerformed private void buttonReloadCardsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonReloadCardsActionPerformed
reloadCardsAndPlayer(); reloadCardsAndPlayer(true);
}//GEN-LAST:event_buttonReloadCardsActionPerformed }//GEN-LAST:event_buttonReloadCardsActionPerformed
private void comboRenderModeItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_comboRenderModeItemStateChanged private void comboRenderModeItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_comboRenderModeItemStateChanged
// render modes are loading on show dialog, so must ignore change event on startup // render modes are loading on show dialog, so must ignore change event on startup
if (this.isVisible()) { if (this.isVisible()) {
reloadCardsAndPlayer(); reloadCardsAndPlayer(false);
} }
}//GEN-LAST:event_comboRenderModeItemStateChanged }//GEN-LAST:event_comboRenderModeItemStateChanged
@ -885,57 +893,57 @@ public class TestCardRenderDialog extends MageDialog {
// Convert to frac in [0.5, 2.0] exponentially // Convert to frac in [0.5, 2.0] exponentially
cardSizeMod = (float) Math.pow(2, sliderFrac); cardSizeMod = (float) Math.pow(2, sliderFrac);
playerSizeMod = (float) Math.pow(2, sliderFrac); playerSizeMod = (float) Math.pow(2, sliderFrac);
reloadCardsAndPlayer(); reloadCardsAndPlayer(false);
}//GEN-LAST:event_sliderSizeStateChanged }//GEN-LAST:event_sliderSizeStateChanged
private void checkBoxGenerateManyCardsItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_checkBoxGenerateManyCardsItemStateChanged private void checkBoxGenerateManyCardsItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_checkBoxGenerateManyCardsItemStateChanged
reloadCardsAndPlayer(); reloadCardsAndPlayer(false);
}//GEN-LAST:event_checkBoxGenerateManyCardsItemStateChanged }//GEN-LAST:event_checkBoxGenerateManyCardsItemStateChanged
private void comboCardIconsPositionItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_comboCardIconsPositionItemStateChanged private void comboCardIconsPositionItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_comboCardIconsPositionItemStateChanged
reloadCardsAndPlayer(); reloadCardsAndPlayer(false);
}//GEN-LAST:event_comboCardIconsPositionItemStateChanged }//GEN-LAST:event_comboCardIconsPositionItemStateChanged
private void spinnerCardIconsMaxVisibleStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_spinnerCardIconsMaxVisibleStateChanged private void spinnerCardIconsMaxVisibleStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_spinnerCardIconsMaxVisibleStateChanged
reloadCardsAndPlayer(); reloadCardsAndPlayer(false);
}//GEN-LAST:event_spinnerCardIconsMaxVisibleStateChanged }//GEN-LAST:event_spinnerCardIconsMaxVisibleStateChanged
private void spinnerCardIconsAdditionalAmountStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_spinnerCardIconsAdditionalAmountStateChanged private void spinnerCardIconsAdditionalAmountStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_spinnerCardIconsAdditionalAmountStateChanged
reloadCardsAndPlayer(); reloadCardsAndPlayer(false);
}//GEN-LAST:event_spinnerCardIconsAdditionalAmountStateChanged }//GEN-LAST:event_spinnerCardIconsAdditionalAmountStateChanged
private void comboCardIconsOrderItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_comboCardIconsOrderItemStateChanged private void comboCardIconsOrderItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_comboCardIconsOrderItemStateChanged
reloadCardsAndPlayer(); reloadCardsAndPlayer(false);
}//GEN-LAST:event_comboCardIconsOrderItemStateChanged }//GEN-LAST:event_comboCardIconsOrderItemStateChanged
private void comboThemeItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_comboThemeItemStateChanged private void comboThemeItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_comboThemeItemStateChanged
// themes list are loading on show dialog, so must ignore change event on startup // themes list are loading on show dialog, so must ignore change event on startup
if (this.isVisible()) { if (this.isVisible()) {
reloadCardsAndPlayer(); reloadCardsAndPlayer(true);
} }
}//GEN-LAST:event_comboThemeItemStateChanged }//GEN-LAST:event_comboThemeItemStateChanged
private void comboCardColorItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_comboCardColorItemStateChanged private void comboCardColorItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_comboCardColorItemStateChanged
// card icon colors list are loading on show dialog, so must ignore change event on startup // card icon colors list are loading on show dialog, so must ignore change event on startup
if (this.isVisible()) { if (this.isVisible()) {
reloadCardsAndPlayer(); reloadCardsAndPlayer(false);
} }
}//GEN-LAST:event_comboCardColorItemStateChanged }//GEN-LAST:event_comboCardColorItemStateChanged
private void comboPlayerStatusItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_comboPlayerStatusItemStateChanged private void comboPlayerStatusItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_comboPlayerStatusItemStateChanged
reloadCardsAndPlayer(); reloadCardsAndPlayer(false);
}//GEN-LAST:event_comboPlayerStatusItemStateChanged }//GEN-LAST:event_comboPlayerStatusItemStateChanged
private void comboPlayerControllerItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_comboPlayerControllerItemStateChanged private void comboPlayerControllerItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_comboPlayerControllerItemStateChanged
reloadCardsAndPlayer(); reloadCardsAndPlayer(false);
}//GEN-LAST:event_comboPlayerControllerItemStateChanged }//GEN-LAST:event_comboPlayerControllerItemStateChanged
private void checkPlayerSmallModeItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_checkPlayerSmallModeItemStateChanged private void checkPlayerSmallModeItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_checkPlayerSmallModeItemStateChanged
reloadCardsAndPlayer(); reloadCardsAndPlayer(false);
}//GEN-LAST:event_checkPlayerSmallModeItemStateChanged }//GEN-LAST:event_checkPlayerSmallModeItemStateChanged
private void checkPlayerAsTargetItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_checkPlayerAsTargetItemStateChanged private void checkPlayerAsTargetItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_checkPlayerAsTargetItemStateChanged
reloadCardsAndPlayer(); reloadCardsAndPlayer(false);
}//GEN-LAST:event_checkPlayerAsTargetItemStateChanged }//GEN-LAST:event_checkPlayerAsTargetItemStateChanged
// Variables declaration - do not modify//GEN-BEGIN:variables // Variables declaration - do not modify//GEN-BEGIN:variables

View file

@ -351,6 +351,6 @@ public enum ThemeType {
} }
// reload card icons and other rendering things from cache - it can depend on current theme // reload card icons and other rendering things from cache - it can depend on current theme
GUISizeHelper.refreshGUIAndCards(); GUISizeHelper.refreshGUIAndCards(true);
} }
} }

View file

@ -2,14 +2,16 @@ package mage.client.util;
import mage.client.MageFrame; import mage.client.MageFrame;
import mage.client.dialog.PreferencesDialog; import mage.client.dialog.PreferencesDialog;
import mage.client.util.gui.GuiDisplayUtil;
import org.mage.card.arcane.CardRenderer; import org.mage.card.arcane.CardRenderer;
import javax.swing.*; import javax.swing.*;
import java.awt.*; import java.awt.*;
import java.util.Locale;
/** /**
* @author LevelX2 * Helper class for GUI
*
* @author LevelX2, JayDi85
*/ */
public final class GUISizeHelper { public final class GUISizeHelper {
@ -83,8 +85,17 @@ public final class GUISizeHelper {
return new Font("Arial", Font.PLAIN, 14); return new Font("Arial", Font.PLAIN, 14);
} }
public static void refreshGUIAndCards() { /**
* Reset all caches and reload all GUI with actual settings.
* Use it after GUI settings change like colors/fonts/sizes.
*
* @param reloadTheme use it after theme changes only
*/
public static void refreshGUIAndCards(boolean reloadTheme) {
calculateGUISizes(); calculateGUISizes();
if (reloadTheme) {
GuiDisplayUtil.refreshThemeSettings();
}
if (MageFrame.getInstance() != null) { if (MageFrame.getInstance() != null) {
MageFrame.getInstance().refreshGUIAndCards(); MageFrame.getInstance().refreshGUIAndCards();
} }

View file

@ -2,7 +2,6 @@ package mage.client.util.gui;
import mage.client.MageFrame; import mage.client.MageFrame;
import mage.client.dialog.PreferencesDialog; import mage.client.dialog.PreferencesDialog;
import static mage.client.dialog.PreferencesDialog.KEY_MAGE_PANEL_LAST_SIZE;
import mage.client.table.PlayersChatPanel; import mage.client.table.PlayersChatPanel;
import mage.client.util.GUISizeHelper; import mage.client.util.GUISizeHelper;
import mage.constants.*; import mage.constants.*;
@ -10,6 +9,7 @@ import mage.view.CardView;
import mage.view.CounterView; import mage.view.CounterView;
import mage.view.PermanentView; import mage.view.PermanentView;
import net.java.truevfs.access.TFile; import net.java.truevfs.access.TFile;
import org.apache.log4j.Logger;
import org.jdesktop.swingx.JXPanel; import org.jdesktop.swingx.JXPanel;
import org.mage.card.arcane.ManaSymbols; import org.mage.card.arcane.ManaSymbols;
import org.mage.card.arcane.UI; import org.mage.card.arcane.UI;
@ -19,9 +19,19 @@ import javax.swing.*;
import java.awt.*; import java.awt.*;
import java.util.List; import java.util.List;
import java.util.*; import java.util.*;
import java.util.stream.Collectors;
import static mage.client.dialog.PreferencesDialog.KEY_MAGE_PANEL_LAST_SIZE;
/**
* Helper class for GUI
*
* @author JayDi85
*/
public final class GuiDisplayUtil { public final class GuiDisplayUtil {
private static final Logger logger = Logger.getLogger(GuiDisplayUtil.class);
private static final Font cardNameFont = new Font("Calibri", Font.BOLD, 15); private static final Font cardNameFont = new Font("Calibri", Font.BOLD, 15);
private static final Insets DEFAULT_INSETS = new Insets(0, 0, 70, 25); private static final Insets DEFAULT_INSETS = new Insets(0, 0, 70, 25);
private static final Insets COMPONENT_INSETS = new Insets(0, 0, 40, 40); private static final Insets COMPONENT_INSETS = new Insets(0, 0, 40, 40);
@ -452,4 +462,62 @@ public final class GuiDisplayUtil {
component.setEnabled(isEnabled); component.setEnabled(isEnabled);
} }
} }
/**
* Fast refresh of GUI settings after theme change.
* Warning, use it for:
* - startup (before any components create)
* - preview only (for settings dialog)
* Existing hidden components can miss new settings (will render with old colors), so only app restart can help.
*/
public static void refreshThemeSettings() {
// apply Nimbus's look and fill
// possible settings:
// https://docs.oracle.com/en%2Fjava%2Fjavase%2F17%2Fdocs%2Fapi%2F%2F/java.desktop/javax/swing/plaf/nimbus/doc-files/properties.html
// enable nimbus
try {
UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
} catch (ClassNotFoundException
| InstantiationException
| IllegalAccessException
| UnsupportedLookAndFeelException e) {
logger.error("Can't apply current theme: " + PreferencesDialog.getCurrentTheme() + " - " + e, e);
}
// enable new style from current theme
//UIManager.put("desktop", new Color(0, 0, 0, 0));
UIManager.put("nimbusBlueGrey", PreferencesDialog.getCurrentTheme().getNimbusBlueGrey()); // buttons, scrollbar background, disabled inputs
UIManager.put("control", PreferencesDialog.getCurrentTheme().getControl()); // window bg
UIManager.put("nimbusLightBackground", PreferencesDialog.getCurrentTheme().getNimbusLightBackground()); // inputs, table rows
UIManager.put("info", PreferencesDialog.getCurrentTheme().getInfo()); // tooltips
UIManager.put("nimbusBase", PreferencesDialog.getCurrentTheme().getNimbusBase()); // title bars, scrollbar foreground
//UIManager.put("nimbusDisabledText", Color.green); // TODO: improve disabled color
//UIManager.put("Table.rowHeight", GUISizeHelper.tableRowHeight);
// for debug only - print full LaF params
if (false) {
System.out.println("");
System.out.println(UIManager.getLookAndFeel().getDefaults().size());
String s = UIManager.getLookAndFeel().getDefaults().keySet().stream()
.map(key -> key + " = " + UIManager.getLookAndFeel().getDefaults().get(key))
.sorted()
.collect(Collectors.joining("\n"));
System.out.println("");
System.out.println(s);
}
// re-render existing components with new style
for (Frame frame : Frame.getFrames()) {
refreshLookAndFill(frame);
}
}
private static void refreshLookAndFill(Window window) {
for (Window childWindow : window.getOwnedWindows()) {
refreshLookAndFill(childWindow);
}
SwingUtilities.updateComponentTreeUI(window);
}
} }

View file

@ -163,15 +163,6 @@ public final class UI {
} }
} }
public static void setSystemLookAndFeel() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
System.err.println("Error setting look and feel:");
ex.printStackTrace();
}
}
public static void setDefaultFont(Font font) { public static void setDefaultFont(Font font) {
for (Object key : Collections.list(UIManager.getDefaults().keys())) { for (Object key : Collections.list(UIManager.getDefaults().keys())) {
Object value = UIManager.get(key); Object value = UIManager.get(key);

View file

@ -721,7 +721,7 @@ public class CardPluginImpl implements CardPlugin {
LOGGER.info("Symbols download finished"); LOGGER.info("Symbols download finished");
dialog.dispose(); dialog.dispose();
ManaSymbols.loadImages(); ManaSymbols.loadImages();
GUISizeHelper.refreshGUIAndCards(); GUISizeHelper.refreshGUIAndCards(false);
} }
} }
} }

View file

@ -713,7 +713,7 @@ public class DownloadPicturesService extends DefaultBoundedRangeModel implements
enableDialogButtons(); enableDialogButtons();
// reset GUI and cards to use new images // reset GUI and cards to use new images
GUISizeHelper.refreshGUIAndCards(); GUISizeHelper.refreshGUIAndCards(false);
} }
static String convertStreamToString(InputStream is) { static String convertStreamToString(InputStream is) {