mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-11 16:26:22 +00:00
Merge pull request #8742 from Jetz72/fixes20250918
Refactor "Unique Cards Only" Setting for Mobile Editor
This commit is contained in:
@@ -85,7 +85,7 @@ public class AdventureDeckEditor extends FDeckEditor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ItemPool<PaperCard> getCardPool(boolean wantUnique) {
|
public ItemPool<PaperCard> getCardPool() {
|
||||||
ItemPool<PaperCard> pool = new ItemPool<>(PaperCard.class);
|
ItemPool<PaperCard> pool = new ItemPool<>(PaperCard.class);
|
||||||
pool.addAll(Current.player().getCards());
|
pool.addAll(Current.player().getCards());
|
||||||
return pool;
|
return pool;
|
||||||
@@ -163,7 +163,7 @@ public class AdventureDeckEditor extends FDeckEditor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ItemPool<PaperCard> getCardPool(boolean wantUnique) {
|
public ItemPool<PaperCard> getCardPool() {
|
||||||
return deckToPreview.getAllCardsInASinglePool(true, true);
|
return deckToPreview.getAllCardsInASinglePool(true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -66,8 +66,8 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
|
|||||||
return gameType == null ? null : gameType.getDeckFormat();
|
return gameType == null ? null : gameType.getDeckFormat();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ItemPool<PaperCard> getCardPool(boolean wantUnique) {
|
public ItemPool<PaperCard> getCardPool() {
|
||||||
return wantUnique ? FModel.getUniqueCardsNoAlt() : FModel.getAllCardsNoAlt();
|
return FModel.getAllCardsNoAlt();
|
||||||
}
|
}
|
||||||
protected Predicate<PaperCard> getCardFilter() { return null; }
|
protected Predicate<PaperCard> getCardFilter() { return null; }
|
||||||
|
|
||||||
@@ -172,10 +172,10 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
|
|||||||
@Override public boolean hasCommander() { return deckFormat.hasCommander(); }
|
@Override public boolean hasCommander() { return deckFormat.hasCommander(); }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ItemPool<PaperCard> getCardPool(boolean wantUnique) {
|
public ItemPool<PaperCard> getCardPool() {
|
||||||
if(this.itemPoolSupplier != null)
|
if(this.itemPoolSupplier != null)
|
||||||
return itemPoolSupplier.get();
|
return itemPoolSupplier.get();
|
||||||
return super.getCardPool(wantUnique);
|
return super.getCardPool();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -1713,7 +1713,7 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
|
|||||||
|
|
||||||
//Clone the pool to ensure we don't mutate it by adding to or removing from this page.
|
//Clone the pool to ensure we don't mutate it by adding to or removing from this page.
|
||||||
//Can override this if that behavior is desired.
|
//Can override this if that behavior is desired.
|
||||||
ItemPool<PaperCard> cardPool = CardPool.createFrom(parentScreen.getEditorConfig().getCardPool(cardManager.getWantUnique()), PaperCard.class);
|
ItemPool<PaperCard> cardPool = CardPool.createFrom(parentScreen.getEditorConfig().getCardPool(), PaperCard.class);
|
||||||
|
|
||||||
if(editorConfig.usePlayerInventory() && currentDeck != null) {
|
if(editorConfig.usePlayerInventory() && currentDeck != null) {
|
||||||
//Remove any items from the pool that are in the deck.
|
//Remove any items from the pool that are in the deck.
|
||||||
@@ -1886,8 +1886,8 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
|
|||||||
menu.addItem(new FCheckBoxMenuItem(Forge.getLocalizer().getMessage("lblUniqueCardsOnly"), cardManager.getWantUnique(), e -> {
|
menu.addItem(new FCheckBoxMenuItem(Forge.getLocalizer().getMessage("lblUniqueCardsOnly"), cardManager.getWantUnique(), e -> {
|
||||||
boolean wantUnique = !cardManager.getWantUnique();
|
boolean wantUnique = !cardManager.getWantUnique();
|
||||||
cardManager.setWantUnique(wantUnique);
|
cardManager.setWantUnique(wantUnique);
|
||||||
refresh();
|
|
||||||
cardManager.getConfig().setUniqueCardsOnly(wantUnique);
|
cardManager.getConfig().setUniqueCardsOnly(wantUnique);
|
||||||
|
cardManager.refresh();
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ public class FDeckImportDialog extends FDialog {
|
|||||||
boolean replacingDeck = !currentDeck.isEmpty() || usingInventory;
|
boolean replacingDeck = !currentDeck.isEmpty() || usingInventory;
|
||||||
this.currentDeck = currentDeck;
|
this.currentDeck = currentDeck;
|
||||||
this.editorConfig = editorConfig;
|
this.editorConfig = editorConfig;
|
||||||
ItemPool<PaperCard> cardPool = editorConfig.getCardPool(false);
|
ItemPool<PaperCard> cardPool = editorConfig.getCardPool();
|
||||||
controller = new DeckImportController(dateTimeCheck, monthDropdown, yearDropdown, replacingDeck);
|
controller = new DeckImportController(dateTimeCheck, monthDropdown, yearDropdown, replacingDeck);
|
||||||
String contents = Forge.getClipboard().getContents();
|
String contents = Forge.getClipboard().getContents();
|
||||||
if (contents == null)
|
if (contents == null)
|
||||||
|
|||||||
@@ -1,10 +1,18 @@
|
|||||||
package forge.itemmanager;
|
package forge.itemmanager;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import com.google.common.collect.ListMultimap;
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import com.google.common.collect.Multimaps;
|
||||||
import forge.Graphics;
|
import forge.Graphics;
|
||||||
|
import forge.StaticData;
|
||||||
import forge.assets.FSkinColor;
|
import forge.assets.FSkinColor;
|
||||||
import forge.assets.FSkinFont;
|
import forge.assets.FSkinFont;
|
||||||
|
import forge.card.CardEdition;
|
||||||
import forge.card.CardRenderer;
|
import forge.card.CardRenderer;
|
||||||
import forge.card.CardZoom;
|
import forge.card.CardZoom;
|
||||||
import forge.item.PaperCard;
|
import forge.item.PaperCard;
|
||||||
@@ -60,6 +68,77 @@ public class CardManager extends ItemManager<PaperCard> {
|
|||||||
return new AdvancedSearchFilter<>(itemManager);
|
return new AdvancedSearchFilter<>(itemManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Iterable<Entry<PaperCard, Integer>> getUnique(Iterable<Entry<PaperCard, Integer>> items) {
|
||||||
|
//TO-maybe-DO: Share logic between this and identical method in desktop.
|
||||||
|
ListMultimap<String, Entry<PaperCard, Integer>> entriesByName = Multimaps.newListMultimap(
|
||||||
|
new TreeMap<>(String.CASE_INSENSITIVE_ORDER), Lists::newArrayList);
|
||||||
|
for (Entry<PaperCard, Integer> item : items) {
|
||||||
|
final String cardName = item.getKey().getName();
|
||||||
|
entriesByName.put(cardName, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now we're ready to go on with retrieving cards to be returned
|
||||||
|
Map<PaperCard, Integer> cardsMap = new HashMap<>();
|
||||||
|
for (String cardName : entriesByName.keySet()) {
|
||||||
|
List<Entry<PaperCard, Integer>> entries = entriesByName.get(cardName);
|
||||||
|
|
||||||
|
ListMultimap<CardEdition, Entry<PaperCard, Integer>> entriesByEdition = Multimaps.newListMultimap(new HashMap<>(), Lists::newArrayList);
|
||||||
|
for (Entry<PaperCard, Integer> entry : entries) {
|
||||||
|
CardEdition ed = StaticData.instance().getCardEdition(entry.getKey().getEdition());
|
||||||
|
if (ed != null)
|
||||||
|
entriesByEdition.put(ed, entry);
|
||||||
|
}
|
||||||
|
if (entriesByEdition.isEmpty())
|
||||||
|
continue; // skip card
|
||||||
|
|
||||||
|
// Try to retain only those editions accepted by the current Card Art Preference Policy
|
||||||
|
Predicate<CardEdition> editionPredicate = ed -> StaticData.instance().getCardArtPreference().accept(ed);
|
||||||
|
List<CardEdition> acceptedEditions = entriesByEdition.keySet().stream().filter(editionPredicate).collect(Collectors.toList());
|
||||||
|
|
||||||
|
// If policy too strict, fall back to getting all editions.
|
||||||
|
if (acceptedEditions.isEmpty())
|
||||||
|
// Policy is too strict for current PaperCard in Entry. Remove any filter
|
||||||
|
acceptedEditions.addAll(entriesByEdition.keySet());
|
||||||
|
|
||||||
|
Entry<PaperCard, Integer> cardEntry = getCardEntryToAdd(entriesByEdition, acceptedEditions);
|
||||||
|
if (cardEntry != null)
|
||||||
|
cardsMap.put(cardEntry.getKey(), cardEntry.getValue());
|
||||||
|
}
|
||||||
|
return cardsMap.entrySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select the Card Art Entry to add, based on current Card Art Preference Order.
|
||||||
|
// This method will prefer the entry currently having an image. If that's not the case,
|
||||||
|
private Entry<PaperCard, Integer> getCardEntryToAdd(ListMultimap<CardEdition, Entry<PaperCard, Integer>> entriesByEdition,
|
||||||
|
List<CardEdition> acceptedEditions) {
|
||||||
|
// Use standard sort + index, for better performance!
|
||||||
|
Collections.sort(acceptedEditions);
|
||||||
|
if (StaticData.instance().cardArtPreferenceIsLatest())
|
||||||
|
Collections.reverse(acceptedEditions);
|
||||||
|
Iterator<CardEdition> editionIterator = acceptedEditions.iterator();
|
||||||
|
Entry<PaperCard, Integer> candidateEntry = null;
|
||||||
|
Entry<PaperCard, Integer> firstCandidateEntryFound = null;
|
||||||
|
while (editionIterator.hasNext() && candidateEntry == null){
|
||||||
|
CardEdition cardEdition = editionIterator.next();
|
||||||
|
// These are now the entries to add to Cards Map
|
||||||
|
List<Entry<PaperCard, Integer>> cardEntries = entriesByEdition.get(cardEdition);
|
||||||
|
Iterator<Entry<PaperCard, Integer>> entriesIterator = cardEntries.iterator();
|
||||||
|
candidateEntry = entriesIterator.hasNext() ? entriesIterator.next() : null;
|
||||||
|
if (candidateEntry != null && firstCandidateEntryFound == null)
|
||||||
|
firstCandidateEntryFound = candidateEntry; // save reference to the first candidate entry found!
|
||||||
|
while ((candidateEntry == null || !candidateEntry.getKey().hasImage()) && entriesIterator.hasNext()) {
|
||||||
|
candidateEntry = entriesIterator.next();
|
||||||
|
if (firstCandidateEntryFound == null)
|
||||||
|
firstCandidateEntryFound = candidateEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (candidateEntry != null && !candidateEntry.getKey().hasImage())
|
||||||
|
candidateEntry = null; // resetting for next edition
|
||||||
|
}
|
||||||
|
return candidateEntry != null ? candidateEntry : firstCandidateEntryFound;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ItemRenderer getListItemRenderer(final CompactModeHandler compactModeHandler) {
|
public ItemRenderer getListItemRenderer(final CompactModeHandler compactModeHandler) {
|
||||||
return new CardListItemRenderer(compactModeHandler);
|
return new CardListItemRenderer(compactModeHandler);
|
||||||
|
|||||||
@@ -728,6 +728,10 @@ public abstract class ItemManager<T extends InventoryItem> extends FContainer im
|
|||||||
|
|
||||||
protected abstract AdvancedSearchFilter<? extends T> createAdvancedSearchFilter();
|
protected abstract AdvancedSearchFilter<? extends T> createAdvancedSearchFilter();
|
||||||
|
|
||||||
|
protected Iterable<Entry<T, Integer>> getUnique(final Iterable<Entry<T, Integer>> items) {
|
||||||
|
return Aggregates.uniqueByLast(items, from -> from.getKey().getName());
|
||||||
|
}
|
||||||
|
|
||||||
public void addFilter(final ItemFilter<? extends T> filter) {
|
public void addFilter(final ItemFilter<? extends T> filter) {
|
||||||
filters.get().add(filter);
|
filters.get().add(filter);
|
||||||
add(filter.getWidget());
|
add(filter.getWidget());
|
||||||
@@ -908,19 +912,29 @@ public abstract class ItemManager<T extends InventoryItem> extends FContainer im
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void updateView(final boolean forceFilter, final Iterable<T> itemsToSelect) {
|
public void updateView(final boolean forceFilter, final Iterable<T> itemsToSelect) {
|
||||||
|
//TO-maybe-DO: Share logic between this and identical method in desktop.
|
||||||
final boolean useFilter = (forceFilter && (filterPredicate != null)) || !isUnfiltered();
|
final boolean useFilter = (forceFilter && (filterPredicate != null)) || !isUnfiltered();
|
||||||
|
|
||||||
if (useFilter || forceFilter) {
|
if (useFilter || this.wantUnique || forceFilter) {
|
||||||
model.clear();
|
this.model.clear();
|
||||||
|
|
||||||
Iterable<Entry<T, Integer>> items = pool;
|
|
||||||
if (useFilter) {
|
|
||||||
Predicate<Entry<T, Integer>> pred = x -> x != null && filterPredicate.test(x.getKey());
|
|
||||||
items = IterableUtil.filter(pool, pred);
|
|
||||||
}
|
|
||||||
model.addItems(items);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (useFilter && this.wantUnique) {
|
||||||
|
final Predicate<Entry<T, Integer>> filterForPool = x -> this.filterPredicate.test(x.getKey());
|
||||||
|
final Iterable<Entry<T, Integer>> items = getUnique(IterableUtil.filter(this.pool, filterForPool));
|
||||||
|
this.model.addItems(items);
|
||||||
|
}
|
||||||
|
else if (useFilter) {
|
||||||
|
final Predicate<Entry<T, Integer>> pred = x -> this.filterPredicate.test(x.getKey());
|
||||||
|
this.model.addItems(IterableUtil.filter(this.pool, pred));
|
||||||
|
}
|
||||||
|
else if (this.wantUnique) {
|
||||||
|
final Iterable<Entry<T, Integer>> items = getUnique(this.pool);
|
||||||
|
this.model.addItems(items);
|
||||||
|
}
|
||||||
|
else if (forceFilter) {
|
||||||
|
this.model.addItems(this.pool);
|
||||||
|
}
|
||||||
currentView.refresh(itemsToSelect, getSelectedIndex(), forceFilter ? 0 : currentView.getScrollValue());
|
currentView.refresh(itemsToSelect, getSelectedIndex(), forceFilter ? 0 : currentView.getScrollValue());
|
||||||
|
|
||||||
//update ratio of # in filtered pool / # in total pool
|
//update ratio of # in filtered pool / # in total pool
|
||||||
|
|||||||
Reference in New Issue
Block a user