Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions Mage.Client/src/main/java/mage/client/cards/DragCardGrid.java
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,8 @@ public interface DragCardGridListener {

void duplicateCards(Collection<CardView> cards);

void markCardsAsFavorite(Collection<CardView> cards);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Must be renamed to FavoriteImage here and other places, there are plans to add favorite cards list with fast access to it from deck editor. It’s not same as favorite images.


void invertCardSelection(Collection<CardView> cards);

void showAll();
Expand Down Expand Up @@ -1181,6 +1183,13 @@ private void duplicateSelection() {
}
}

private void markAsFavorite() {
Collection<CardView> toFave = dragCardList();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Must have menu to add single card to favorite or whole set to favorite.

for (DragCardGridListener l : listeners) {
l.markCardsAsFavorite(toFave);
}
}

private void invertSelection() {
Collection<CardView> toInvert = allCards;
for (DragCardGridListener l : listeners) {
Expand Down Expand Up @@ -1980,6 +1989,10 @@ private void showCardRightClickMenu(@SuppressWarnings("unused") final CardView c
JMenuItem duplicateSelection = new JMenuItem("Duplicate selected cards");
duplicateSelection.addActionListener(e2 -> duplicateSelection());
menu.add(duplicateSelection);

JMenuItem markAsFavorite = new JMenuItem("Mark selected card editions as favorite");
markAsFavorite.addActionListener(e2 -> markAsFavorite());
menu.add(markAsFavorite);
}
menu.show(e.getComponent(), e.getX(), e.getY());
}
Expand Down
23 changes: 23 additions & 0 deletions Mage.Client/src/main/java/mage/client/deckeditor/DeckArea.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import mage.client.util.Event;
import mage.client.util.GUISizeHelper;
import mage.client.util.Listener;
import mage.client.preference.MagePreferences;
import mage.view.CardView;
import mage.view.CardsView;

Expand Down Expand Up @@ -113,6 +114,17 @@ public void duplicateCards(Collection<CardView> cards) {
deckList.addCardView(newCard, card);
}
}

@Override
public void markCardsAsFavorite(Collection<CardView> cards) {
deckList.deselectAll();
for (CardView card : cards) {
String name = card.getName();
String setCode = card.getExpansionSetCode();
String cardNumber = card.getCardNumber();
MagePreferences.setFavoriteCard(name, cardNumber, setCode);
}
}

@Override
public void invertCardSelection(Collection<CardView> cards) {
Expand Down Expand Up @@ -154,6 +166,17 @@ public void duplicateCards(Collection<CardView> cards) {
}
}

@Override
public void markCardsAsFavorite(Collection<CardView> cards) {
deckList.deselectAll();
for (CardView card : cards) {
String name = card.getName();
String setCode = card.getExpansionSetCode();
String cardNumber = card.getCardNumber();
MagePreferences.setFavoriteCard(name, cardNumber, setCode);
}
}

@Override
public void invertCardSelection(Collection<CardView> cards) {
// Invert Selection
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -759,6 +759,7 @@ private void importFromFile(java.awt.event.ActionEvent evt) {
MageFrame.getDesktop().setCursor(new Cursor(Cursor.WAIT_CURSOR));
try {
DeckImporter importer = DeckImporter.getDeckImporter(file.getPath());
importer.setPreferences(MageFrame.getPreferences());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Must change the logic: import original cards, press right click to add/remove/apply favorite sets/cards versions. Do not modify import code with hidden features.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not modify import code with hidden features.
Could you clarify this? If this is about passing preferences as a field to the importer, I could not figure out a way to add favorite logic to the import process without doing that.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Import feature must import original cards and do not modify it by hidden logic without user notification/interaction.

Deck editor has full access to deck and cards data, so you can modify it from a deck editor, no needs in import code. Look for code example in oldVersionDeck method.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UX logic for a user:

  • open/import/construct original deck;
  • press special button/menu like “Replace all cards by favorite versions”;
  • check and save final result;


if (importer != null) {
StringBuilder errorMessages = new StringBuilder();
Expand Down Expand Up @@ -822,7 +823,13 @@ private void importFromClipboardWithAppend(ActionEvent evt) {
StringBuilder errorMessages = new StringBuilder();
MageFrame.getDesktop().setCursor(new Cursor(Cursor.WAIT_CURSOR));
try {
Deck deckToAppend = Deck.load(DeckImporter.importDeckFromFile(tempDeckPath, errorMessages, false), true, true);
DeckImporter deckImporter = DeckImporter.getDeckImporter(tempDeckPath);
DeckCardLists deckCardLists = new DeckCardLists();
if (deckImporter != null) {
deckImporter.setPreferences(MageFrame.getPreferences());
deckCardLists = deckImporter.importDeck(tempDeckPath, errorMessages, false);
}
Deck deckToAppend = Deck.load(deckCardLists, true, true);
processAndShowImportErrors(errorMessages);
this.deck = Deck.append(deckToAppend, this.deck);
refreshDeck(false, true);
Expand Down Expand Up @@ -924,7 +931,14 @@ private boolean loadDeck(String file, boolean saveAutoFixedFile) {
MageFrame.getDesktop().setCursor(new Cursor(Cursor.WAIT_CURSOR));
try {
StringBuilder errorMessages = new StringBuilder();
Deck newDeck = Deck.load(DeckImporter.importDeckFromFile(file, errorMessages, saveAutoFixedFile), true, true);
DeckImporter deckImporter = DeckImporter.getDeckImporter(file);
DeckCardLists deckCardLists = new DeckCardLists();
if (deckImporter != null) {
deckImporter.setPreferences(MageFrame.getPreferences());
deckCardLists = deckImporter.importDeck(file, errorMessages, saveAutoFixedFile);
}

Deck newDeck = Deck.load(deckCardLists, true, true);
processAndShowImportErrors(errorMessages);

if (newDeck != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public final class MagePreferences {
private static final String KEY_PASSWORD = "password";
private static final String KEY_EMAIL = "email";
private static final String KEY_AUTO_CONNECT = "autoConnect";
private static final String KEY_FAVORITE_CARD_PREFIX = "favoriteCard";
private static final String NODE_KEY_IGNORE_LIST = "ignoreListString";
private static final String NODE_KEY_RESTORE_SESSIONS_LIST = "restoreSessionsListString";

Expand Down Expand Up @@ -115,6 +116,26 @@ public static void setAutoConnect(boolean autoConnect) {
prefs().putBoolean(KEY_AUTO_CONNECT, autoConnect);
}

public static String getFavoriteCardNumber(String cardName) {
String setAndNumber = prefs().get(prefixedKey(KEY_FAVORITE_CARD_PREFIX, cardName), "");
if (setAndNumber != null && !setAndNumber.equals("")) {
return setAndNumber.split("##")[1];
}
return "";
}

public static String getFavoriteCardSet(String cardName) {
String setAndNumber = prefs().get(prefixedKey(KEY_FAVORITE_CARD_PREFIX, cardName), "");
if (setAndNumber != null && !setAndNumber.equals("")) {
return setAndNumber.split("##")[0];
}
return "";
}

public static void setFavoriteCard(String cardName, String cardNumber, String setCode) {
prefs().put(prefixedKey(KEY_FAVORITE_CARD_PREFIX, cardName), setCode + "##" + cardNumber);
Copy link
Member

@JayDi85 JayDi85 Nov 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don’t like to use a java prefs to store user defined data. There are popular bugs with settings/data lost, e.g. after system java update. Current logic with subfolder and one record per card is fine anyway.

p.s. Images folder with additional text files can be more useful in the future like favorite_image_sets.txt and favorite_image_cards.txt And it will allow easy review and edit for a users.

}

public static void addIgnoredUser(String serverAddress, String username) {
ignoreListNode(serverAddress).putBoolean(username, true);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import java.io.File;
import java.util.Locale;
import java.util.prefs.Preferences;
import java.util.Scanner;

/**
Expand Down Expand Up @@ -47,6 +48,12 @@ public void setFixedLine(String fixedLine) {

private static final String[] SIDEBOARD_MARKS = new String[]{"//sideboard", "sb: "};

protected Preferences prefs = null;

public void setPreferences(Preferences prefs) {
this.prefs = prefs;
}

public static DeckImporter getDeckImporter(String file) {
if (file == null) {
return null;
Expand Down
12 changes: 12 additions & 0 deletions Mage/src/main/java/mage/cards/decks/importer/TxtDeckImporter.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
import java.util.prefs.Preferences;

/**
* Deck import: text deck, compatible with MTGO and many other apps/services
Expand All @@ -21,6 +22,7 @@ public class TxtDeckImporter extends PlainTextDeckImporter {
private static final String[] SET_VALUES = new String[]{"lands", "creatures", "planeswalkers", "other spells", "sideboard cards",
"Instant", "Land", "Enchantment", "Artifact", "Sorcery", "Planeswalker", "Creature"};
private static final Set<String> IGNORE_NAMES = new HashSet<>(Arrays.asList(SET_VALUES));
private static final String KEY_FAVORITE_CARD_PREFIX = "favoriteCard";

private boolean sideboard = false;
private boolean switchSideboardByEmptyLine = true; // all cards after first empty line will be sideboard (like mtgo format)
Expand Down Expand Up @@ -129,6 +131,16 @@ protected void readLine(String line, DeckCardLists deckList, FixedInfo fixedInfo
wasCardLines = true;

CardInfo cardInfo = CardRepository.instance.findPreferredCoreExpansionCard(lineName);

if (prefs != null) {
String favSetAndNumber = prefs.get(KEY_FAVORITE_CARD_PREFIX + '/' + lineName, "");
if (favSetAndNumber != null && !favSetAndNumber.equals("")) {
String favoriteSet = favSetAndNumber.split("##")[0];
String favoriteNumber = favSetAndNumber.split("##")[1];
cardInfo = CardRepository.instance.findCard(favoriteSet, favoriteNumber);
}
}

if (cardInfo == null) {
sbMessage.append("Could not find card: '").append(lineName).append("' at line ").append(lineCount).append('\n');
} else {
Expand Down