Skip to content

Commit bccf128

Browse files
committed
feat: add "any card" option to sd filter
1 parent 504b1b2 commit bccf128

File tree

4 files changed

+57
-22
lines changed

4 files changed

+57
-22
lines changed

src/components/changes-needed/FilterErrorOptions.tsx

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {
88
showModal
99
} from "decky-frontend-lib";
1010
import { VFC, Fragment, useState, useContext } from "react";
11-
import { FilterType, TabFilterSettings } from "../filters/Filters";
11+
import { FilterType, SdCardParamType, TabFilterSettings } from "../filters/Filters";
1212
import { FixMergeFilterModal } from "../modals/FixMergeFilterModal";
1313
import { ErrorPanelTabNameContext } from "../../state/ErrorPanelNameContext";
1414
import { DestructiveModal } from '../generic/DestructiveModal';
@@ -163,12 +163,17 @@ const SDCardFilterErrorOption: VFC<FilterErrorOptionsProps<'sd card'>> = ({ isMe
163163
const dropdownOptions: DropdownOption[] = [
164164
{
165165
label: "Inserted Card",
166-
data: undefined,
166+
data: SdCardParamType.INSTALLED,
167167
},
168168
{
169169
label: "Specific Card",
170170
options: cardsAndGames.map(([card]) => { return { label: card.name || card.uid, data: card.uid } })
171-
}];
171+
},
172+
{
173+
label: "Any Card",
174+
data: SdCardParamType.ANY
175+
}
176+
];
172177

173178
function onChange({data}: SingleDropdownOption) {
174179
const updatedFilter = { ...filter };
@@ -178,7 +183,7 @@ const SDCardFilterErrorOption: VFC<FilterErrorOptionsProps<'sd card'>> = ({ isMe
178183

179184
return (
180185
<Field
181-
label="Selected Collection"
186+
label="Selected Card"
182187
description={
183188
<div className="filter-entry">
184189
<Focusable style={{
@@ -189,8 +194,8 @@ const SDCardFilterErrorOption: VFC<FilterErrorOptionsProps<'sd card'>> = ({ isMe
189194
<Focusable style={{
190195
width: "calc(100% - 55px)"
191196
}}>
192-
<Dropdown rgOptions={dropdownOptions} selectedOption={filter.params.card} onChange={onChange} />
193-
</Focusable>
197+
<Dropdown rgOptions={dropdownOptions} selectedOption={filter.params.card ?? SdCardParamType.INSTALLED} onChange={onChange} />
198+
</Focusable> {/* ^ back compat for undefined as installed card */}
194199
<Focusable style={{
195200
marginLeft: "10px",
196201
width: "45px"

src/components/filters/FilterOptions.tsx

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import { IoGameController, IoGrid } from "react-icons/io5";
1717
import { BsWindow } from "react-icons/bs";
1818
import { IconType } from "react-icons/lib";
1919

20-
import { FilterType, ReviewScoreType, TabFilterSettings, ThresholdCondition, TimeUnit, compatCategoryToLabel } from "./Filters";
20+
import { FilterType, ReviewScoreType, SdCardParamType, TabFilterSettings, ThresholdCondition, TimeUnit, compatCategoryToLabel } from "./Filters";
2121
import { TabMasterContextProvider, useTabMasterContext } from "../../state/TabMasterContext";
2222
import { ModeMultiSelect } from "../multi-selects/ModeMultiSelect";
2323
import { EditMergeFilterModal } from "../modals/EditMergeFilterModal";
@@ -963,12 +963,17 @@ const SDCardFilterOptions: VFC<FilterOptionsProps<'sd card'>> = ({ index, setCon
963963
const dropdownOptions: DropdownOption[] = [
964964
{
965965
label: "Inserted Card",
966-
data: undefined,
966+
data: SdCardParamType.INSTALLED,
967967
},
968968
{
969969
label: "Specific Card",
970970
options: cardsAndGames.map(([card]) => { return { label: card.name || card.uid, data: card.uid } })
971-
}];
971+
},
972+
{
973+
label: "Any Card",
974+
data: SdCardParamType.ANY
975+
}
976+
];
972977

973978
function onChange({data}: SingleDropdownOption) {
974979
const updatedFilter = { ...filter };
@@ -981,8 +986,8 @@ const SDCardFilterOptions: VFC<FilterOptionsProps<'sd card'>> = ({ index, setCon
981986
return (
982987
<Field
983988
label="Micro SD Card"
984-
description={<Dropdown rgOptions={dropdownOptions} selectedOption={filter.params.card} onChange={onChange} disabled={!isMicroSDeckInstalled} />}
985-
/>
989+
description={<Dropdown rgOptions={dropdownOptions} selectedOption={filter.params.card ?? SdCardParamType.INSTALLED} onChange={onChange} disabled={!isMicroSDeckInstalled} />}
990+
/> //^ back compat for undefined as installed card
986991
);
987992
};
988993

src/components/filters/FilterPreview.tsx

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Fragment, VFC, createElement } from "react";
2-
import { FilterIcons, FilterType, TabFilterSettings, compatCategoryToLabel } from "./Filters";
2+
import { FilterIcons, FilterType, SdCardParamType, TabFilterSettings, compatCategoryToLabel } from "./Filters";
33
import { dateToLabel } from '../generic/DatePickers';
44
import { capitalizeEachWord } from '../../lib/Utils';
55
import { MicroSDeckInterop } from '../../lib/controllers/MicroSDeckInterop';
@@ -146,9 +146,19 @@ const AchievementsFilterPreview: VFC<FilterPreviewProps<'achievements'>> = ({ fi
146146
};
147147

148148
const SDCardFilterPreview: VFC<FilterPreviewProps<'sd card'>> = ({ filter }) => {
149-
const isInsertCard = !filter.params.card;
150-
const card = (MicroSDeckInterop.isInstallOk() && window.MicroSDeck?.CardsAndGames.find(([card]) => card.uid === filter.params.card)?.[0].name) || filter.params.card;
151-
return <FilterPreviewGeneric filter={filter} displayData={isInsertCard ? 'Inserted Card' : card} isInverted={filter.inverted} />;
149+
let label: string;
150+
switch (filter.params.card) {
151+
case SdCardParamType.ANY:
152+
label = "Any";
153+
break;
154+
case SdCardParamType.INSTALLED:
155+
case undefined:
156+
label = "Inserted";
157+
break;
158+
default:
159+
label = (MicroSDeckInterop.isInstallOk() && window.MicroSDeck?.CardsAndGames.find(([card]) => card.uid === filter.params.card)?.[0].name) || filter.params.card;
160+
}
161+
return <FilterPreviewGeneric filter={filter} displayData={label} isInverted={filter.inverted} />;
152162
}
153163

154164
/**

src/components/filters/Filters.tsx

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,19 @@ import { FaAward, FaBan, FaCalendarDays, FaCloudArrowDown, FaCompactDisc, FaList
1010
import { BsClockHistory, BsRegex } from "react-icons/bs";
1111
import { LuCombine } from "react-icons/lu";
1212
import { LogController } from "../../lib/controllers/LogController";
13+
import { CardAndGames } from '@cebbinghaus/microsdeck';
1314

1415
export type FilterType = 'collection' | 'installed' | 'regex' | 'friends' | 'tags' | 'whitelist' | 'blacklist' | 'merge' | 'platform' | 'deck compatibility' | 'review score' | 'time played' | 'size on disk' | 'release date' | 'purchase date' | 'last played' | 'family sharing' | 'demo' | 'streamable' | 'steam features' | 'achievements' | 'sd card';
1516

1617
export type TimeUnit = 'minutes' | 'hours' | 'days';
1718
export type ThresholdCondition = 'above' | 'below';
1819
export type ReviewScoreType = 'metacritic' | 'steampercent';
1920

21+
export enum SdCardParamType {
22+
INSTALLED = 0,
23+
ANY
24+
};
25+
2026
type CollectionFilterParams = {
2127
id: SteamCollection['id'],
2228
/**
@@ -56,7 +62,7 @@ type AchievementsFilterParams = {
5662
thresholdType: "count" | "percent",
5763
condition: ThresholdCondition
5864
}
59-
type SdCardParams = { card: undefined | string }; //use undefined for currently inserted card
65+
type SdCardParams = { card: SdCardParamType | string | undefined }; //inserted card/ any card/ card uid (undefined value is legacy)
6066

6167
// appOverview.rt_purchased_time
6268

@@ -120,7 +126,7 @@ export const FilterDefaultParams: { [key in FilterType]: FilterParams<key> } = {
120126
"streamable": { isStreamable: true },
121127
"steam features": { features: [], mode: 'and' },
122128
"achievements": { threshold: 10, thresholdType: "percent", condition: 'above' },
123-
"sd card": { card: undefined }
129+
"sd card": { card: SdCardParamType.INSTALLED }
124130
}
125131

126132
/**
@@ -372,7 +378,7 @@ export function validateFilter(filter: TabFilterSettings<FilterType>): Validatio
372378
const cardFilter = filter as TabFilterSettings<'sd card'>;
373379

374380
let passed = true;
375-
if (MicroSDeckInterop.isInstallOk() && window.MicroSDeck!.Enabled && cardFilter.params.card) {
381+
if (MicroSDeckInterop.isInstallOk() && window.MicroSDeck!.Enabled && typeof cardFilter.params.card === 'string') {
376382
const cardsAndGames = window.MicroSDeck!.CardsAndGames || [];
377383

378384
if (!cardsAndGames.find(([card]) => cardFilter.params.card === card.uid)) {
@@ -620,11 +626,20 @@ export class Filter {
620626
}
621627
},
622628
'sd card': (params: FilterParams<'sd card'>, appOverview: SteamAppOverview) => {
623-
const card = params.card === undefined ? window.MicroSDeck?.CurrentCardAndGames : window.MicroSDeck?.CardsAndGames?.find(([card]) => card.uid == params.card);
624-
629+
const isOnCard = (card: CardAndGames) => !!card[1].find((game) => +game.uid == appOverview.appid);
630+
let card: CardAndGames | undefined;
631+
switch (params.card) {
632+
case SdCardParamType.ANY:
633+
return window.MicroSDeck?.CardsAndGames?.find(isOnCard);
634+
case SdCardParamType.INSTALLED:
635+
case undefined:
636+
card = window.MicroSDeck?.CurrentCardAndGames;
637+
break;
638+
default:
639+
card = window.MicroSDeck?.CardsAndGames?.find(([card]) => card.uid == params.card);
640+
}
625641
if (!card) return false;
626-
627-
return !!card[1].find((game) => +game.uid == appOverview.appid);
642+
return isOnCard(card);
628643
}
629644
};
630645

0 commit comments

Comments
 (0)