Skip to content

Commit

Permalink
Merge pull request #202 from Tormak9970/dev
Browse files Browse the repository at this point in the history
chore: build beta-compatible pre-release
  • Loading branch information
Tormak9970 authored Jul 29, 2024
2 parents 8f44487 + 102e590 commit 565c2b6
Show file tree
Hide file tree
Showing 16 changed files with 428 additions and 148 deletions.
41 changes: 0 additions & 41 deletions .github/workflows/commit-lint.yml

This file was deleted.

19 changes: 14 additions & 5 deletions src/components/CustomTabContainer.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { EditableTabSettings } from "./modals/EditTabModal";
import { TabFilterSettings, FilterType, Filter } from "./filters/Filters";
import { filtersHaveType, getIncludedCategoriesFromBitField } from "../lib/Utils";
import { gamepadTabbedPageClasses } from "decky-frontend-lib";
import { gamepadTabbedPageClasses, showModal } from "decky-frontend-lib";
import { SortOverrideMessage } from './modals/SortOverrideMessage';

/**
* Wrapper for injecting custom tabs.
Expand All @@ -16,6 +17,7 @@ export class CustomTabContainer implements TabContainer {
categoriesToInclude: number;
autoHide: boolean;
dependsOnMicroSDeck: boolean;
sortByOverride: number;

/**
* Creates a new CustomTabContainer.
Expand All @@ -26,8 +28,9 @@ export class CustomTabContainer implements TabContainer {
* @param filtersMode boolean operator for top level filters
* @param categoriesToInclude A bit field of which categories should be included in the tab.
* @param autoHide Whether or not the tab should automatically be hidden if it's collection is empty.
* @param sortByOverride The eSortBy number to force use for sorting. -1 ignores override.
*/
constructor(id: string, title: string, position: number, filterSettingsList: TabFilterSettings<FilterType>[], filtersMode: LogicalMode, categoriesToInclude: number, autoHide: boolean) {
constructor(id: string, title: string, position: number, filterSettingsList: TabFilterSettings<FilterType>[], filtersMode: LogicalMode, categoriesToInclude: number, autoHide: boolean, sortByOverride: number) {
this.id = id;
this.title = title;
this.position = position;
Expand All @@ -36,6 +39,7 @@ export class CustomTabContainer implements TabContainer {
this.categoriesToInclude = categoriesToInclude;
this.autoHide = autoHide;
this.dependsOnMicroSDeck = false;
this.sortByOverride = sortByOverride;

//@ts-ignore
this.collection = {
Expand All @@ -57,17 +61,21 @@ export class CustomTabContainer implements TabContainer {
this.checkMicroSDeckDependency();
}

getActualTab(TabContentComponent: TabContentComponent, sortingProps: Omit<TabContentProps, 'collection'>, footer: SteamTab['footer'], collectionAppFilter: any, isMicroSDeckInstalled: boolean): SteamTab | null {
getActualTab(TabContentComponent: TabContentComponent, sortingProps: Omit<TabContentProps, 'collection'>, footer: SteamTab['footer'] = {}, collectionAppFilter: any, isMicroSDeckInstalled: boolean): SteamTab | null {
if (!isMicroSDeckInstalled && this.dependsOnMicroSDeck) return null;
if (this.autoHide && this.collection.visibleApps.length === 0) return null;

const showSortOverride = () => showModal(<SortOverrideMessage eSortBy={this.sortByOverride} />);
if (this.sortByOverride !== -1) footer.onOptionsButton = showSortOverride;

return {
title: this.title,
id: this.id,
footer: footer,
content: <TabContentComponent
collection={this.collection}
{...sortingProps}
setSortBy={sortingProps.setSortBy}
eSortBy={this.sortByOverride === -1 ? sortingProps.eSortBy : this.sortByOverride}
showSortingContextMenu={this.sortByOverride === -1 ? sortingProps.showSortingContextMenu : showSortOverride}
/>,
renderTabAddon: () => {
return <span className={gamepadTabbedPageClasses.TabCount}>
Expand Down Expand Up @@ -117,6 +125,7 @@ export class CustomTabContainer implements TabContainer {
this.categoriesToInclude = updatedTabInfo.categoriesToInclude;
this.filters = updatedTabInfo.filters;
this.autoHide = updatedTabInfo.autoHide;
this.sortByOverride = updatedTabInfo.sortByOverride;
this.buildCollection();
this.checkMicroSDeckDependency();
}
Expand Down
131 changes: 120 additions & 11 deletions src/components/filters/FilterOptions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -534,7 +534,7 @@ const SizeOnDiskFilterOptions: VFC<FilterOptionsProps<'size on disk'>> = ({ inde
};

/**
* The options for a time played filter.
* The options for a release date filter.
*/
const ReleaseDateFilterOptions: VFC<FilterOptionsProps<'release date'>> = ({ index, setContainingGroupFilters, filter, containingGroupFilters }) => {
const [date, setDate] = useState<DateObj | undefined>(filter.params.date);
Expand Down Expand Up @@ -630,6 +630,103 @@ const ReleaseDateFilterOptions: VFC<FilterOptionsProps<'release date'>> = ({ ind
);
};

/**
* The options for a purchase date filter.
*/
const PurchaseDateFilterOptions: VFC<FilterOptionsProps<'purchase date'>> = ({ index, setContainingGroupFilters, filter, containingGroupFilters }) => {
const [date, setDate] = useState<DateObj | undefined>(filter.params.date);
const [dateIncludes, setDateIncludes] = useState<DateIncludes>(filter.params.date ? (filter.params.date.day === undefined ? (filter.params.date.month === undefined ? DateIncludes.yearOnly : DateIncludes.monthYear) : DateIncludes.dayMonthYear) : DateIncludes.dayMonthYear);
const [thresholdType, setThresholdType] = useState<ThresholdCondition>(filter.params.condition);
const [byDaysAgo, setByDaysAgo] = useState(filter.params.daysAgo !== undefined);
const [daysAgo, setDaysAgo] = useState<number>(filter.params.daysAgo ?? 30);

function onDateChange(dateSelection: DateSelection) {
const updatedFilter = { ...filter };
updatedFilter.params.date = dateSelection.data;
const updatedFilters = [...containingGroupFilters];
updatedFilters[index] = updatedFilter;
setContainingGroupFilters(updatedFilters);
setDate(dateSelection.data);
}

function onThreshTypeChange({ data: threshType }: { data: ThresholdCondition; }) {
const updatedFilter = { ...filter };
updatedFilter.params.condition = threshType;
const updatedFilters = [...containingGroupFilters];
updatedFilters[index] = updatedFilter;
setContainingGroupFilters(updatedFilters);
setThresholdType(threshType);
}

function onByDaysAgoChange(byDaysAgo: boolean) {
const updatedFilter = { ...filter };
if (byDaysAgo) {
delete updatedFilter.params.date;
updatedFilter.params.daysAgo = daysAgo;
} else {
delete updatedFilter.params.daysAgo;
updatedFilter.params.date = date;
}
const updatedFilters = [...containingGroupFilters];
updatedFilters[index] = updatedFilter;
setContainingGroupFilters(updatedFilters);
setByDaysAgo(byDaysAgo);
}

function onSliderChange(value: number) {
const updatedFilter = { ...filter };
updatedFilter.params.daysAgo = value;
const updatedFilters = [...containingGroupFilters];
updatedFilters[index] = updatedFilter;
setContainingGroupFilters(updatedFilters);
setDaysAgo(value);
}

return (
<Field label={`Purchased ${byDaysAgo ? `${daysAgo} day${daysAgo === 1 ? '' : 's'} ago or ${thresholdType === 'above' ? 'later' : 'earlier'}` : `${dateIncludes === DateIncludes.dayMonthYear ? 'on' : 'in'} or ${thresholdType === 'above' ? 'after' : 'before'}...`}`}
description={
<Focusable style={{ display: 'flex', flexDirection: 'row' }}>
{byDaysAgo ?
<Slider value={daysAgo} min={0} max={3000} onChange={onSliderChange} /> :
<DatePicker
focusDropdowns={true}
modalType='simple'
buttonContainerStyle={{ flex: 1 }}
onChange={onDateChange}
dateIncludes={dateIncludes}
selectedDate={date}
toLocaleStringOptions={{ dateStyle: 'long' }}
animate={true}
transparencyMode={EnhancedSelectorTransparencyMode.selection}
focusRingMode={EnhancedSelectorFocusRingMode.transparentOnly}
/>}
<div style={{ margin: '0 10px' }}>
<Dropdown
rgOptions={[
{ label: 'By Day', data: DateIncludes.dayMonthYear },
{ label: 'By Month', data: DateIncludes.monthYear },
{ label: 'By Year', data: DateIncludes.yearOnly },
{ label: 'By Days Ago', data: 'byDaysAgo' }
]}
selectedOption={dateIncludes}
onChange={option => {
if (option.data === 'byDaysAgo') {
onByDaysAgoChange(true);
} else {
if (byDaysAgo) onByDaysAgoChange(false);
setDateIncludes(option.data);
}
}}
/>
</div>
<div>
<Dropdown rgOptions={[{ label: 'Earliest', data: 'above' }, { label: 'Latest', data: 'below' }]} selectedOption={thresholdType} onChange={onThreshTypeChange} />
</div>
</Focusable>}
/>
);
};

/**
* The options for a last played filter.
*/
Expand Down Expand Up @@ -811,36 +908,46 @@ const SteamFeatureFilterOptions: VFC<FilterOptionsProps<'steam features'>> = ({
* The options for a achievements filter.
*/
const AchievementsFilterOptions: VFC<FilterOptionsProps<'achievements'>> = ({ index, setContainingGroupFilters, filter, containingGroupFilters }) => {
const [value, setValue] = useState<number>(filter.params.completionPercentage);
const [thresholdType, setThresholdType] = useState<ThresholdCondition>(filter.params.condition);
const [value, setValue] = useState<number>(filter.params.threshold);
const [thresholdType, setThresholdType] = useState<"percent" | "count">(filter.params.thresholdType);
const [thresholdCondition, setThresholdCondition] = useState<ThresholdCondition>(filter.params.condition);

function updateFilter(threshold: number, threshType: ThresholdCondition) {
function updateFilter(threshold: number, threshCondition: ThresholdCondition, threshType: "percent" | "count") {
const updatedFilter = { ...filter };
updatedFilter.params.completionPercentage = threshold;
updatedFilter.params.condition = threshType;
updatedFilter.params.threshold = threshold;
updatedFilter.params.condition = threshCondition;
updatedFilter.params.thresholdType = threshType;
const updatedFilters = [...containingGroupFilters];
updatedFilters[index] = updatedFilter;
setContainingGroupFilters(updatedFilters);
}

function onSliderChange(value: number) {
updateFilter(value, thresholdType);
updateFilter(value, thresholdCondition, thresholdType);
setValue(value);
}

function onThreshTypeChange({ data: threshType }: { data: ThresholdCondition; }) {
updateFilter(value, threshType);
function onThreshConditionChange({ data: threshCondition }: { data: ThresholdCondition; }) {
updateFilter(value, threshCondition, thresholdType);
setThresholdCondition(threshCondition);
}

function onThreshTypeChange({ data: threshType }: { data: "count" | "percent"; }) {
updateFilter(value, thresholdCondition, threshType);
setThresholdType(threshType);
}

return (
<Field
label={`${value}% or ${thresholdType === 'above' ? 'more' : 'less'} achievements completed`}
label={`${value}${thresholdType === "percent" ? "%" : ""} or ${thresholdCondition === 'above' ? 'more' : 'less'} achievements completed`}
description={
<Focusable style={{ display: 'flex', flexDirection: 'row' }}>
<Slider value={value} min={0} max={100} onChange={onSliderChange} />
<div style={{ marginLeft: '12px' }}>
<Dropdown rgOptions={[{ label: 'At least', data: 'above' }, { label: 'At most', data: 'below' }]} selectedOption={thresholdType} onChange={onThreshTypeChange} />
<Dropdown rgOptions={[{ label: 'At least', data: 'above' }, { label: 'At most', data: 'below' }]} selectedOption={thresholdCondition} onChange={onThreshConditionChange} />
</div>
<div style={{ marginLeft: '12px' }}>
<Dropdown rgOptions={[{ label: 'Count', data: 'count' }, { label: 'Percent', data: 'percent' }]} selectedOption={thresholdType} onChange={onThreshTypeChange} />
</div>
</Focusable>}
/>
Expand Down Expand Up @@ -914,6 +1021,8 @@ export const FilterOptions: VFC<FilterOptionsProps<FilterType>> = ({ index, filt
return <SizeOnDiskFilterOptions index={index} filter={filterCopy as TabFilterSettings<'size on disk'>} containingGroupFilters={containingGroupFilters} setContainingGroupFilters={setContainingGroupFilters} />;
case "release date":
return <ReleaseDateFilterOptions index={index} filter={filterCopy as TabFilterSettings<'release date'>} containingGroupFilters={containingGroupFilters} setContainingGroupFilters={setContainingGroupFilters} />;
case "purchase date":
return <PurchaseDateFilterOptions index={index} filter={filterCopy as TabFilterSettings<'purchase date'>} containingGroupFilters={containingGroupFilters} setContainingGroupFilters={setContainingGroupFilters} />;
case "last played":
return <LastPlayedFilterOptions index={index} filter={filterCopy as TabFilterSettings<'last played'>} containingGroupFilters={containingGroupFilters} setContainingGroupFilters={setContainingGroupFilters} />;
case "family sharing":
Expand Down
20 changes: 18 additions & 2 deletions src/components/filters/FilterPreview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,20 @@ const ReleaseDateFilterPreview: VFC<FilterPreviewProps<'release date'>> = ({ fil
return <FilterPreviewGeneric filter={filter} displayData={displayData} />;
};

const PurchaseDateFilterPreview: VFC<FilterPreviewProps<'purchase date'>> = ({ filter }) => {
let displayData: string;

if (filter.params.date) {
const { day, month, year } = filter.params.date;
displayData = `${!day ? 'In' : 'On'} or ${filter.params.condition === 'above' ? 'after' : 'before'} ${dateToLabel(year, month, day, { dateStyle: 'long' })}`;
} else {
const daysAgo = filter.params.daysAgo;
displayData = `${daysAgo} day${daysAgo === 1 ? '' : 's'} ago or ${filter.params.condition === 'above' ? 'later' : 'earlier'}`;
}

return <FilterPreviewGeneric filter={filter} displayData={displayData} />;
};

const LastPlayedFilterPreview: VFC<FilterPreviewProps<'last played'>> = ({ filter }) => {
let displayData: string;

Expand Down Expand Up @@ -127,8 +141,8 @@ const SteamFeaturesFilterPreview: VFC<FilterPreviewProps<'steam features'>> = ({
};

const AchievementsFilterPreview: VFC<FilterPreviewProps<'achievements'>> = ({ filter }) => {
const { completionPercentage, condition } = filter.params;
return <FilterPreviewGeneric filter={filter} displayData={`${completionPercentage}% or ${condition === 'above' ? 'more' : 'less'} achievements completed`} />;
const { threshold, thresholdType, condition } = filter.params;
return <FilterPreviewGeneric filter={filter} displayData={`${threshold}${thresholdType === "percent" ? "%" : ""} or ${condition === 'above' ? 'more' : 'less'} achievements completed`} />;
};

const SDCardFilterPreview: VFC<FilterPreviewProps<'sd card'>> = ({ filter }) => {
Expand Down Expand Up @@ -171,6 +185,8 @@ export const FilterPreview: VFC<FilterPreviewProps<FilterType>> = ({ filter }) =
return <SizeOnDiskFilterPreview filter={filter as TabFilterSettings<'size on disk'>} />;
case "release date":
return <ReleaseDateFilterPreview filter={filter as TabFilterSettings<'release date'>} />;
case "purchase date":
return <PurchaseDateFilterPreview filter={filter as TabFilterSettings<'purchase date'>} />;
case "last played":
return <LastPlayedFilterPreview filter={filter as TabFilterSettings<'last played'>} />;
case "family sharing":
Expand Down
Loading

0 comments on commit 565c2b6

Please sign in to comment.