Skip to content

Commit

Permalink
Merge pull request #310 from noahm/filter-by-folder
Browse files Browse the repository at this point in the history
Allow filtering songs by folder
  • Loading branch information
noahm authored Mar 20, 2024
2 parents 245967c + 8cf5a50 commit 1cbbe62
Show file tree
Hide file tree
Showing 13 changed files with 310 additions and 79 deletions.
38 changes: 20 additions & 18 deletions scripts/validate.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import songsSchema from "../songs.schema.json" assert { type: "json" };
const schemaLocation = "src/models/SongData.ts";

function validateContents(dataFile) {
const errors = [];
const errors = new Set();

const allKeys = [
...dataFile.meta.styles,
Expand All @@ -20,58 +20,60 @@ function validateContents(dataFile) {
const styles = new Set(dataFile.meta.styles);
const difficulties = new Set(dataFile.meta.difficulties.map((d) => d.key));
const flags = new Set(dataFile.meta.flags);
const folders = new Set(dataFile.meta.folders);

if (dataFile.defaults.style && !styles.has(dataFile.defaults.style)) {
errors.push("default style is not listed in meta");
errors.add("default style is not listed in meta");
}

if (dataFile.defaults.difficulties.some((d) => !difficulties.has(d))) {
errors.push("some default difficulties are missing from meta");
errors.add("some default difficulties are missing from meta");
}

// removed to allow for hidden flags like "plus" charts in SMX
// if (dataFile.defaults.flags.some((d) => !flags.has(d))) {
// errors.push("some default flags are missing from meta");
// errors.add("some default flags are missing from meta");
// }

if (dataFile.defaults.lowerLvlBound > dataFile.defaults.upperLvlBound) {
errors.push("default level bounds are reversed");
errors.add("default level bounds are reversed");
}

if (dataFile.i18n.ja) {
for (const key of allKeys) {
if (!(dataFile.i18n.en[key] && dataFile.i18n.ja[key])) {
errors.push("missing translation for " + key);
if (!dataFile.i18n.en[key]) {
errors.add("missing translation for " + key);
}
if (
difficulties.has(key) &&
!(dataFile.i18n.en["$abbr"][key] && dataFile.i18n.ja["$abbr"][key])
) {
errors.push("missing abbreviated translation for " + key);
if (difficulties.has(key) && !dataFile.i18n.en["$abbr"][key]) {
errors.add("missing abbreviated translation for " + key);
}
}
}

for (const song of dataFile.songs) {
if (dataFile.meta.folders && song.folder) {
if (!folders.has(song.folder)) {
errors.add(`top level folders list is missing ${song.folder}`);
}
}
if (song.jacket) {
const jacketPath = join(jacketsDir, song.jacket);
if (!existsSync(jacketPath)) {
errors.push(`missing jacket image ${song.jacket}`);
errors.add(`missing jacket image ${song.jacket}`);
}
}

for (const chart of song.charts) {
if (!styles.has(chart.style)) {
errors.push(`unrecognized style "${chart.style}" used by ${song.name}`);
errors.add(`unrecognized style "${chart.style}" used by ${song.name}`);
}
if (!difficulties.has(chart.diffClass)) {
errors.push(
errors.add(
`unrecognized diffClass "${chart.diffClass}" used by ${song.name}`,
);
}
if (dataFile.meta.usesDrawGroups) {
if (!chart.drawGroup) {
errors.push(`${song.name} is missing a draw group`);
errors.add(`${song.name} is missing a draw group`);
}
}
}
Expand All @@ -93,7 +95,7 @@ for (const dataFile of dataFileNames) {

if (result.valid) {
const consistencyErrors = validateContents(songData);
if (consistencyErrors.length) {
if (consistencyErrors.size) {
consistencyErrors.forEach((err) => console.error(" * " + err));
console.log(`\n${dataFile} has inconsistent data!`);
hasError = true;
Expand Down
5 changes: 5 additions & 0 deletions songs.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@
"$ref": "#/definitions/uniqueStringArr",
"description": "List of all special flags one might filter songs by"
},
"folders": {
"$ref": "#/definitions/uniqueStringArr",
"description": "List of all possible folders, in order"
},
"usesDrawGroups": {
"type": "boolean"
},
Expand All @@ -75,6 +79,7 @@
"style": { "type": "string" },
"difficulties": { "$ref": "#/definitions/uniqueStringArr" },
"flags": { "$ref": "#/definitions/uniqueStringArr" },
"folders": { "$ref": "#/definitions/uniqueStringArr" },
"lowerLvlBound": { "type": "number" },
"upperLvlBound": { "type": "number" }
}
Expand Down
11 changes: 9 additions & 2 deletions src/apply-default-config.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,20 @@ export function ApplyDefaultConfig({ defaults, granularResolution }: Props) {
}

useConfigState.setState(() => {
const { lowerLvlBound, upperLvlBound, flags, difficulties, style } =
defaults;
const {
lowerLvlBound,
upperLvlBound,
flags,
difficulties,
folders,
style,
} = defaults;
const ret: Partial<ConfigState> = {
lowerBound: lowerLvlBound,
upperBound: upperLvlBound,
flags: new Set(flags),
difficulties: new Set(difficulties),
folders: new Set(folders),
style,
};
if (!granularResolution) {
Expand Down
1 change: 1 addition & 0 deletions src/assets/i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"orderByAction": "Re-order by pick/ban",
"style": "Style",
"difficulties": "Difficulties",
"folders": "Folders",
"include": "Include",
"tabs": {
"general": "General",
Expand Down
5 changes: 4 additions & 1 deletion src/card-draw.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,10 @@ export function songIsValid(
if (forPocketPick && !config.constrainPocketPicks) {
return true;
}
return !song.flags || song.flags.every((f) => config.flags.has(f));
return (
(!song.folder || !config.folders.size || config.folders.has(song.folder)) &&
(!song.flags || song.flags.every((f) => config.flags.has(f)))
);
}

/** returns true if chart matches configured difficulty/style/lvl/flags */
Expand Down
2 changes: 2 additions & 0 deletions src/config-persistence.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ function buildPersistedConfig(): PersistedConfigV1 {
...configState,
difficulties: Array.from(configState.difficulties),
flags: Array.from(configState.flags),
folders: Array.from(configState.folders),
};
const ret: PersistedConfigV1 = {
version: 1,
Expand Down Expand Up @@ -133,6 +134,7 @@ async function loadPersistedConfig(saved: PersistedConfigV1) {
...migrateOldNames(saved.configState),
difficulties: new Set(saved.configState.difficulties),
flags: new Set(saved.configState.flags),
folders: new Set(saved.configState.folders),
});
}

Expand Down
2 changes: 2 additions & 0 deletions src/config-state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export interface ConfigState {
forceDistribution: boolean;
constrainPocketPicks: boolean;
style: string;
folders: ReadonlySet<string>;
difficulties: ReadonlySet<string>;
flags: ReadonlySet<string>;
showEligibleCharts: boolean;
Expand All @@ -40,6 +41,7 @@ export const useConfigState = createWithEqualityFn<ConfigState>(
forceDistribution: true,
constrainPocketPicks: true,
style: "",
folders: new Set(),
difficulties: new Set(),
flags: new Set(),
showEligibleCharts: false,
Expand Down
72 changes: 68 additions & 4 deletions src/controls/controls-drawer.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
Button,
ButtonGroup,
Card,
Checkbox,
Classes,
Expand All @@ -20,6 +21,8 @@ import {
CaretDown,
CaretRight,
Plus,
SmallTick,
SmallCross,
} from "@blueprintjs/icons";
import { useMemo, useState } from "react";
import { shallow } from "zustand/shallow";
Expand Down Expand Up @@ -120,15 +123,19 @@ export default function ControlsDrawer() {

function FlagSettings() {
const { t } = useIntl();
const [dataSetName, gameData] = useDrawState(
(s) => [s.dataSetName, s.gameData],
const [dataSetName, gameData, hasFlags] = useDrawState(
(s) => [s.dataSetName, s.gameData, !!s.gameData?.meta.flags.length],
shallow,
);
const [updateState, selectedFlags] = useConfigState(
(s) => [s.update, s.flags],
shallow,
);

if (!hasFlags) {
return false;
}

return (
<FormGroup label={t("controls.include")}>
{gameData?.meta.flags.map((key) => (
Expand All @@ -154,10 +161,66 @@ function FlagSettings() {
);
}

function FolderSettings() {
const { t } = useIntl();
const availableFolders = useDrawState((s) => s.gameData?.meta.folders);
const dataSetName = useDrawState((s) => s.dataSetName);
const [updateState, selectedFolders] = useConfigState(
(s) => [s.update, s.folders],
shallow,
);

if (!availableFolders?.length) {
return null;
}

return (
<FormGroup
label={t("controls.folders")}
style={{ opacity: selectedFolders.size ? undefined : 0.8 }}
>
<ButtonGroup className={styles.smallText}>
<Button
small
icon={<SmallTick />}
onClick={() => updateState({ folders: new Set(availableFolders) })}
>
All
</Button>
<Button
small
icon={<SmallCross />}
onClick={() => updateState({ folders: new Set() })}
>
Ignore Folders
</Button>
</ButtonGroup>
{availableFolders.map((folder, idx) => (
<Checkbox
key={`${dataSetName}:${idx}`}
label={folder}
value={folder}
checked={selectedFolders.has(folder)}
onChange={() =>
updateState((s) => {
const newFolders = new Set(s.folders);
if (newFolders.has(folder)) {
newFolders.delete(folder);
} else {
newFolders.add(folder);
}
return { folders: newFolders };
})
}
/>
))}
</FormGroup>
);
}

function GeneralSettings() {
const { t } = useIntl();
const gameData = useDrawState((s) => s.gameData);
const hasFlags = useDrawState((s) => !!s.gameData?.meta.flags.length);
const configState = useConfigState();
const {
useWeights,
Expand Down Expand Up @@ -394,7 +457,8 @@ function GeneralSettings() {
/>
))}
</FormGroup>
{hasFlags && <FlagSettings />}
<FlagSettings />
<FolderSettings />
</Card>
</Collapse>
<FormGroup>
Expand Down
4 changes: 4 additions & 0 deletions src/controls/controls.css
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@
margin-right: 25px;
}

.smallText button {
font-size: 8pt !important;
}

.plus {
margin-top: 30px;
margin-left: -23px;
Expand Down
29 changes: 21 additions & 8 deletions src/game-data-utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,18 +36,31 @@ export function getAvailableLevels(
return [];
}

let getLevelForChart = (chart: Chart) =>
useGranular ? chart.sanbaiTier || chart.lvl : chart.lvl;
if (gameData.meta.usesDrawGroups) {
getLevelForChart = (chart) => chart.drawGroup || chart.lvl;
}
const levelSet = new Set<number>();
gameData.songs.forEach((song) => {
song.charts.forEach((chart) => levelSet.add(getLevelForChart(chart)));
});
for (const song of gameData.songs) {
for (const chart of song.charts) {
levelSet.add(
chartLevelOrTier(chart, useGranular, gameData.meta.usesDrawGroups),
);
}
}
return [...levelSet].sort((a, b) => a - b);
}

// export function getAvailableFolders(gameData: GameData | null): string[] {
// if (gameData === null) {
// return [];
// }

// const folderSet = new Set<string>();
// for (const song of gameData.songs) {
// if (song.folder) {
// folderSet.add(song.folder);
// }
// }
// return [...folderSet].sort((a, b) => (a < b ? -1 : 1));
// }

export function getDiffAbbr(gameData: GameData, diffClass: string) {
return ((gameData.i18n.en as I18NDict)["$abbr"] as I18NDict)[
diffClass
Expand Down
Loading

0 comments on commit 1cbbe62

Please sign in to comment.