Public Access
feat(play-next): add series and studio rows
This commit is contained in:
1 parent
df3d6d2537
commit
e041c71cf8
5 files changed
+41
-8
No files matched your search
@@ -28,8 +28,9 @@ To Be Played is split into three repositories:
|
||||
- **Coming games**: a game that is not released yet (and nobody played) shows a "Coming <date>" badge in the library, on
|
||||
the details page, in the stat game lists and on the public profile. The pile counts only the games Core sends in
|
||||
`pileGames`, so coming games are not on it; Core never picks them.
|
||||
- **What to play next** (`/play-next`): four rows of up to 3 backlog games each: up next (your own backlog order),
|
||||
because you played (a similar game for each of your 3 most played), longest on your list, and mood picks. A time
|
||||
- **What to play next** (`/play-next`): six rows of up to 3 backlog games each: up next (your own backlog order),
|
||||
next in series (the next part of a series you played), because you played (a similar game for each of your 3 most
|
||||
played), same studio (a developer you played), longest on your list, and mood picks. A time
|
||||
budget (up to 5 / 15 / 40 h or any) filters all rows; a mood (story, co-op, chill, action, scary from IGDB; speedrun
|
||||
from speedrun.com) only the mood row. Each row has its own reroll without repeats, and "Start playing" in one click.
|
||||
On a phone each row scrolls sideways.
|
||||
|
||||
+5
-1
@@ -431,14 +431,18 @@
|
||||
},
|
||||
"PLAY_NEXT": {
|
||||
"TITLE": "Was spiele ich als Nächstes?",
|
||||
"SUBTITLE": "Spiele aus deinem Backlog in vier Reihen: als Nächstes in deiner Reihenfolge, wie Spiele, die du viel gespielt hast, am längsten wartend und nach Stimmung. Wähle eine Dauer für alle Reihen und eine Stimmung für die letzte.",
|
||||
"SUBTITLE": "Spiele aus deinem Backlog in sechs Reihen: als Nächstes in deiner Reihenfolge, der nächste Teil einer Reihe, die du gespielt hast, wie Spiele, die du viel gespielt hast, von einem Studio, das du gespielt hast, am längsten wartend und nach Stimmung. Wähle eine Dauer für alle Reihen und eine Stimmung für die letzte.",
|
||||
"REASON": {
|
||||
"SIMILAR": "Weil du {{name}} gespielt hast ({{playtime}})",
|
||||
"SERIES": "Reihe: {{name}}",
|
||||
"STUDIO": "Von {{name}}",
|
||||
"LONGEST": "Auf deiner Liste seit {{date}}"
|
||||
},
|
||||
"CATEGORY": {
|
||||
"NEXT_UP": "Als Nächstes",
|
||||
"SERIES": "Nächster Teil der Reihe",
|
||||
"SIMILAR": "Weil du gespielt hast",
|
||||
"STUDIO": "Vom selben Studio",
|
||||
"LONGEST": "Am längsten auf deiner Liste",
|
||||
"RANDOM": "Zufallstreffer",
|
||||
"MOOD": "Stimmung: {{mood}}"
|
||||
|
||||
+5
-1
@@ -431,14 +431,18 @@
|
||||
},
|
||||
"PLAY_NEXT": {
|
||||
"TITLE": "What to play next",
|
||||
"SUBTITLE": "Games from your backlog in four rows: next in your order, like games you played a lot, waiting longest, and by mood. Pick a length for all rows and a mood for the last one.",
|
||||
"SUBTITLE": "Games from your backlog in six rows: next in your order, the next part of a series you played, like games you played a lot, from a studio you played, waiting longest, and by mood. Pick a length for all rows and a mood for the last one.",
|
||||
"REASON": {
|
||||
"SIMILAR": "Because you played {{name}} ({{playtime}})",
|
||||
"SERIES": "Series: {{name}}",
|
||||
"STUDIO": "From {{name}}",
|
||||
"LONGEST": "On your list since {{date}}"
|
||||
},
|
||||
"CATEGORY": {
|
||||
"NEXT_UP": "Up next",
|
||||
"SERIES": "Next in series",
|
||||
"SIMILAR": "Because you played",
|
||||
"STUDIO": "Same studio",
|
||||
"LONGEST": "Longest on your list",
|
||||
"RANDOM": "Random picks",
|
||||
"MOOD": "Mood: {{mood}}"
|
||||
|
||||
@@ -27,7 +27,7 @@ const BUDGETS = [
|
||||
// games without that data.
|
||||
const MOODS = ['ANY', 'STORY', 'COOP', 'CHILL', 'ACTION', 'SCARY', 'SPEEDRUN'];
|
||||
// The rows in the order Core sends them; RANDOM is the mood row.
|
||||
const ROW_ORDER = ['NEXT_UP', 'SIMILAR', 'LONGEST', 'RANDOM'];
|
||||
const ROW_ORDER = ['NEXT_UP', 'SERIES', 'SIMILAR', 'STUDIO', 'LONGEST', 'RANDOM'];
|
||||
// The backend reads only this many excludes. With a bigger backlog the oldest seen games can come back.
|
||||
const MAX_EXCLUDES = 100;
|
||||
const ROW_CLASS = 'flex gap-4 overflow-x-auto snap-x snap-mandatory pb-2 sm:grid sm:grid-cols-3 sm:overflow-visible';
|
||||
@@ -253,6 +253,12 @@ const reasonText = (reason, t, language) => {
|
||||
playtime: formatPlaytime(reason.anchorPlaytimeMinutes),
|
||||
});
|
||||
}
|
||||
if (reason?.source === 'SERIES') {
|
||||
return t('PLAY_NEXT.REASON.SERIES', {name: reason.seriesName});
|
||||
}
|
||||
if (reason?.source === 'STUDIO') {
|
||||
return t('PLAY_NEXT.REASON.STUDIO', {name: reason.studioName});
|
||||
}
|
||||
if (reason?.source === 'LONGEST') {
|
||||
return t('PLAY_NEXT.REASON.LONGEST', {date: formatDate(reason.firstSeenAt, language, {dateStyle: 'medium'})});
|
||||
}
|
||||
|
||||
@@ -18,7 +18,9 @@ const game = (appid, extra = {}) => ({
|
||||
const row = (source, ...games) => ({source, games});
|
||||
const ALL = () => [
|
||||
row('NEXT_UP', game(1), game(2)),
|
||||
row('SERIES', game(6, {reason: {source: 'SERIES', seriesName: 'Mass Effect'}})),
|
||||
row('SIMILAR', game(3, {reason: {source: 'SIMILAR', anchorAppid: 9, anchorName: 'Celeste', anchorPlaytimeMinutes: 600}})),
|
||||
row('STUDIO', game(8, {reason: {source: 'STUDIO', studioName: 'BioWare'}})),
|
||||
row('LONGEST', game(4, {reason: {source: 'LONGEST', firstSeenAt: '2024-03-12T10:00:00Z'}})),
|
||||
row('RANDOM', game(5, {reason: {source: 'RANDOM'}})),
|
||||
];
|
||||
@@ -75,8 +77,8 @@ describe('PlayNextPage', () => {
|
||||
|
||||
await screen.findByText('Game 1');
|
||||
expect(screen.getAllByRole('heading', {level: 2}).map((h) => h.textContent)).toEqual([
|
||||
'PLAY_NEXT.CATEGORY.NEXT_UP', 'PLAY_NEXT.CATEGORY.SIMILAR', 'PLAY_NEXT.CATEGORY.LONGEST',
|
||||
'PLAY_NEXT.CATEGORY.RANDOM']);
|
||||
'PLAY_NEXT.CATEGORY.NEXT_UP', 'PLAY_NEXT.CATEGORY.SERIES', 'PLAY_NEXT.CATEGORY.SIMILAR',
|
||||
'PLAY_NEXT.CATEGORY.STUDIO', 'PLAY_NEXT.CATEGORY.LONGEST', 'PLAY_NEXT.CATEGORY.RANDOM']);
|
||||
const params = pickerUrls()[0];
|
||||
expect(params.has('count')).toBe(false);
|
||||
expect(params.has('category')).toBe(false);
|
||||
@@ -175,6 +177,20 @@ describe('PlayNextPage', () => {
|
||||
expect(pickerUrls()[2].has('mood')).toBe(false);
|
||||
});
|
||||
|
||||
it('rerolls the series row with category=SERIES and without a mood', async () => {
|
||||
mockRows(ALL(), {SERIES: [row('SERIES', game(10))]});
|
||||
renderPage();
|
||||
await screen.findByText('Game 1');
|
||||
fireEvent.click(screen.getByRole('button', {name: 'PLAY_NEXT.MOOD.STORY'}));
|
||||
await screen.findByText('Game 5');
|
||||
|
||||
fireEvent.click(rerollOf('PLAY_NEXT.CATEGORY.SERIES'));
|
||||
|
||||
await screen.findByText('Game 10');
|
||||
expect(pickerUrls()[2].get('category')).toBe('SERIES');
|
||||
expect(pickerUrls()[2].has('mood')).toBe(false);
|
||||
});
|
||||
|
||||
it('starts a row over when it has no unseen game left', async () => {
|
||||
mockBackend((params) => {
|
||||
if (!params.get('category')) return ALL();
|
||||
@@ -228,12 +244,14 @@ describe('PlayNextPage', () => {
|
||||
expect(await screen.findByText('PLAY_NEXT.EMPTY_MOOD')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('shows a reason line for the similar and longest rows only', async () => {
|
||||
it('shows a reason line for the series, similar, studio and longest rows only', async () => {
|
||||
mockRows();
|
||||
|
||||
renderPage();
|
||||
|
||||
expect(await screen.findByText('PLAY_NEXT.REASON.SIMILAR')).toBeTruthy();
|
||||
expect(screen.getByText('PLAY_NEXT.REASON.SERIES')).toBeTruthy();
|
||||
expect(screen.getByText('PLAY_NEXT.REASON.STUDIO')).toBeTruthy();
|
||||
expect(screen.getByText('PLAY_NEXT.REASON.LONGEST')).toBeTruthy();
|
||||
expect(screen.queryByText(/PLAY_NEXT\.REASON\.(RANDOM|NEXT_UP)/)).toBeNull();
|
||||
});
|
||||
|
||||
Reference in new issue
Block a user