fix(web): refresh Home on explicit Home click
loadHomeData now takes a force flag; navigating to Home via a click (not back/forward) invalidates the home rows' API cache so they re-fetch and the random row re-randomizes — matching the Android re-tap behavior. CHANGELOG: note the Home-refresh fix under 1.0. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
211b8ec6c2
commit
58dacbabc3
3 files changed
+10
-8
No files matched your search
@@ -70,6 +70,7 @@ Versioning: two-part `MAJOR.MINOR` — each release bumps the minor (features an
|
|||||||
- **Android** — Download crash on Android 15 (targetSdk 35): `FOREGROUND_SERVICE_TYPE_DATA_SYNC` is banned for apps targeting API 35; WorkManager's expedited path used it and the resulting exception killed the app ~1.5 s after tapping download. Fixed by dropping `setExpedited()` and all foreground-service use from `DownloadWorker` — downloads run as silent background work with progress shown in the Offline tab
|
- **Android** — Download crash on Android 15 (targetSdk 35): `FOREGROUND_SERVICE_TYPE_DATA_SYNC` is banned for apps targeting API 35; WorkManager's expedited path used it and the resulting exception killed the app ~1.5 s after tapping download. Fixed by dropping `setExpedited()` and all foreground-service use from `DownloadWorker` — downloads run as silent background work with progress shown in the Offline tab
|
||||||
- **Android** — Offline detail screen flashed open then immediately returned: its initial empty state (before Room emitted) was mistaken for "deleted". Now shows a brief spinner until loaded, and only leaves when the last song is actually removed
|
- **Android** — Offline detail screen flashed open then immediately returned: its initial empty state (before Room emitted) was mistaken for "deleted". Now shows a brief spinner until loaded, and only leaves when the last song is actually removed
|
||||||
- **Android** — Lyrics autoscroll: rewrote centering to use the active line's *measured* position in a `LazyColumn` instead of a fixed line-height estimate. Eliminates the stutter and the downward drift on wrapped (multi-line) lyrics — the active line now tracks smoothly and sits at a natural ~40 %-from-top reading anchor
|
- **Android** — Lyrics autoscroll: rewrote centering to use the active line's *measured* position in a `LazyColumn` instead of a fixed line-height estimate. Eliminates the stutter and the downward drift on wrapped (multi-line) lyrics — the active line now tracks smoothly and sits at a natural ~40 %-from-top reading anchor
|
||||||
|
- **Web** — Home now refreshes on an explicit Home click (matching Android): the album rows re-fetch and the random row re-randomizes instead of serving the 5-minute cache. Back/forward navigation still keeps the cached state
|
||||||
|
|
||||||
### Internal
|
### Internal
|
||||||
- **Android** — Offline system: `Room` DB (`novasonic_offline.db`) with `downloaded_tracks`, `download_groups`, `group_track_cross_refs`; `OfflineRepository` holds hot `StateFlow` maps for O(1) local-path lookups; `DownloadWorker` streams audio + cover art via `HttpURLConnection` to `context.filesDir/offline/{audio|covers}/`. `MusicRepository.streamUrl()` checks local files first, so playback uses the `file://` URI on every entry point
|
- **Android** — Offline system: `Room` DB (`novasonic_offline.db`) with `downloaded_tracks`, `download_groups`, `group_track_cross_refs`; `OfflineRepository` holds hot `StateFlow` maps for O(1) local-path lookups; `DownloadWorker` streams audio + cover art via `HttpURLConnection` to `context.filesDir/offline/{audio|covers}/`. `MusicRepository.streamUrl()` checks local files first, so playback uses the `file://` URI on every entry point
|
||||||
|
|||||||
+8
-7
@@ -1,6 +1,6 @@
|
|||||||
import { S } from '../state.js';
|
import { S } from '../state.js';
|
||||||
import { esc } from '../utils.js';
|
import { esc } from '../utils.js';
|
||||||
import { api, apiCached, apiIsCached, coverUrl, fetchRomajiIndex, dispArtistById, dispAlbumName, cacheArtistSortNames } from '../api.js';
|
import { api, apiCached, apiIsCached, invalidateApiCache, coverUrl, fetchRomajiIndex, dispArtistById, dispAlbumName, cacheArtistSortNames } from '../api.js';
|
||||||
import { makeCard, makeAlbumCard, makeSongItem } from '../ui/components.js';
|
import { makeCard, makeAlbumCard, makeSongItem } from '../ui/components.js';
|
||||||
import { playQueue } from '../player/player.js';
|
import { playQueue } from '../player/player.js';
|
||||||
// Circular — safe (called inside event handlers)
|
// Circular — safe (called inside event handlers)
|
||||||
@@ -32,7 +32,7 @@ const _greetN = [
|
|||||||
'Time to escape into music', 'Pick something great',
|
'Time to escape into music', 'Pick something great',
|
||||||
];
|
];
|
||||||
|
|
||||||
export async function loadHomeData() {
|
export async function loadHomeData(force = false) {
|
||||||
const name = S.cfg.user || '';
|
const name = S.cfg.user || '';
|
||||||
const g = name
|
const g = name
|
||||||
? `${_greetW[Math.floor(Math.random() * _greetW.length)]} ${name}`
|
? `${_greetW[Math.floor(Math.random() * _greetW.length)]} ${name}`
|
||||||
@@ -42,10 +42,10 @@ export async function loadHomeData() {
|
|||||||
|
|
||||||
loadHeroCard();
|
loadHeroCard();
|
||||||
loadGenreSection();
|
loadGenreSection();
|
||||||
loadAlbumRow('home-newest', 'getAlbumList2', '&type=newest&size=20');
|
loadAlbumRow('home-newest', 'getAlbumList2', '&type=newest&size=20', force);
|
||||||
loadAlbumRow('home-recent', 'getAlbumList2', '&type=recent&size=20');
|
loadAlbumRow('home-recent', 'getAlbumList2', '&type=recent&size=20', force);
|
||||||
loadAlbumRow('home-random', 'getAlbumList2', '&type=random&size=20');
|
loadAlbumRow('home-random', 'getAlbumList2', '&type=random&size=20', force);
|
||||||
loadAlbumRow('home-frequent', 'getAlbumList2', '&type=frequent&size=20');
|
loadAlbumRow('home-frequent', 'getAlbumList2', '&type=frequent&size=20', force);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadHeroCard() {
|
async function loadHeroCard() {
|
||||||
@@ -194,9 +194,10 @@ export async function loadGenreDetail(g) {
|
|||||||
songs.forEach((s, i) => list.appendChild(makeSongItem(s, i, songs)));
|
songs.forEach((s, i) => list.appendChild(makeSongItem(s, i, songs)));
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function loadAlbumRow(id, method, extra) {
|
export async function loadAlbumRow(id, method, extra, force = false) {
|
||||||
const c = document.getElementById(id);
|
const c = document.getElementById(id);
|
||||||
if(!c) return;
|
if(!c) return;
|
||||||
|
if (force) invalidateApiCache(method, extra); // re-fetch (re-randomizes) on explicit Home click
|
||||||
if (!apiIsCached(method, extra)) c.innerHTML = '<div class="spinner"></div>';
|
if (!apiIsCached(method, extra)) c.innerHTML = '<div class="spinner"></div>';
|
||||||
try {
|
try {
|
||||||
const [r] = await Promise.all([
|
const [r] = await Promise.all([
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ export function navigate(page, data=null) {
|
|||||||
if(['discover','new-releases','recommendations','random','spotify-importer'].includes(page)) switchNavMode('discover');
|
if(['discover','new-releases','recommendations','random','spotify-importer'].includes(page)) switchNavMode('discover');
|
||||||
else if(['home','artists','albums','starred','playlists'].includes(page)) switchNavMode('library');
|
else if(['home','artists','albums','starred','playlists'].includes(page)) switchNavMode('library');
|
||||||
|
|
||||||
if(page==='home') loadHomeData();
|
if(page==='home') loadHomeData(!S._navJumping); // explicit Home click refreshes; back/forward keeps state
|
||||||
if(page==='artists' && !document.getElementById('artists-grid').children.length) loadArtists();
|
if(page==='artists' && !document.getElementById('artists-grid').children.length) loadArtists();
|
||||||
if(page==='albums' && !document.getElementById('albums-grid').children.length) loadAlbums();
|
if(page==='albums' && !document.getElementById('albums-grid').children.length) loadAlbums();
|
||||||
if(page==='starred') loadStarred();
|
if(page==='starred') loadStarred();
|
||||||
|
|||||||
Reference in new issue
Block a user