feat(mobile): offline downloads, persistent event queue and offline start (M5)
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 1m7s
ci / docker / docker (образы собираются — их сервер собирает сам при обновлении) (push) Canceled after 4m15s
ci / ts / ts (packages + web) (push) Canceled after 17m42s
ci / mobile / mobile (Metro-бандл Android) (push) Canceled after 18m52s

- Downloads queue (2 parallel, Wi-Fi only by default) stores files under
  the app's document directory and track metadata in SQLite; Collection
  gets a Downloads tab, album and player screens get download buttons.
- Player plays downloaded files and local covers; My Wave falls back to
  a shuffle of downloaded tracks when the server is unreachable.
- Playback events that fail on the network are kept in SQLite and sent
  when the connection returns.
- AuthSession can open offline with the cached user and fetches an
  access token before the first request once online.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
mrleo1nidandClaude Opus 5.5 committed 2026-10-20 13:02:47 +03:00
1 parent 765345e0f4
commit be34ee5361
22 files changed
+881 -387

No files matched your search

+32
View File
@@ -0,0 +1,32 @@
import * as SQLite from 'expo-sqlite';
let db: Promise<SQLite.SQLiteDatabase> | null = null;
/**
* Локальная база офлайн-режима (docs/mobile.md#офлайн). `owner` — хэш «сервер + пользователь»:
* скачанное и неотправленные события одного аккаунта не видны другому.
*/
export function getDb(): Promise<SQLite.SQLiteDatabase> {
db ??= (async () => {
const d = await SQLite.openDatabaseAsync('pipu.db');
await d.execAsync(`
PRAGMA journal_mode = WAL;
CREATE TABLE IF NOT EXISTS downloads (
owner TEXT NOT NULL,
track_id TEXT NOT NULL,
track TEXT NOT NULL,
status TEXT NOT NULL,
bytes INTEGER NOT NULL DEFAULT 0,
added_at INTEGER NOT NULL,
PRIMARY KEY (owner, track_id)
);
CREATE TABLE IF NOT EXISTS pending_events (
id INTEGER PRIMARY KEY AUTOINCREMENT,
owner TEXT NOT NULL,
body TEXT NOT NULL
);
`);
return d;
})();
return db;
}