feat(mobile): Skia wave, wave player view, themes and playback settings (M5)
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 1m30s
ci / mobile / mobile (Metro-бандл Android) (push) Successful in 2m57s
ci / ts / ts (packages + web) (push) Successful in 1m16s
ci / docker / docker (образы собираются — их сервер собирает сам при обновлении) (push) Successful in 33s
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 1m30s
ci / mobile / mobile (Metro-бандл Android) (push) Successful in 2m57s
ci / ts / ts (packages + web) (push) Successful in 1m16s
ci / docker / docker (образы собираются — их сервер собирает сам при обновлении) (push) Successful in 33s
- My Wave is rendered with react-native-skia on the UI thread; physics and colour helpers moved to @pipu/core (wave-anim) and shared with web. - Full-screen player honours ui_prefs.mobile_player (cover / wave). - Theme switching (dark / light / system) via a theme context and useColors() across all screens. - Profile: theme, wave variant, player view, sound quality sheet (Wi-Fi / mobile / downloads), recent-tracks cache clearing on next cold start, and a change-password sheet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
756e915ff9
commit
ed063d3763
28 files changed
+923
-188
No files matched your search
@@ -0,0 +1,67 @@
|
||||
import * as FileSystem from 'expo-file-system';
|
||||
import * as SecureStore from 'expo-secure-store';
|
||||
|
||||
export type Quality = 'original' | 'high' | 'medium' | 'low';
|
||||
export const QUALITIES: readonly Quality[] = ['original', 'high', 'medium', 'low'];
|
||||
|
||||
/** Качество звука по типу сети и для загрузок (настройка устройства, на сервер не уходит). */
|
||||
export interface QualityPrefs {
|
||||
wifi: Quality;
|
||||
cellular: Quality;
|
||||
download: Quality;
|
||||
}
|
||||
|
||||
const QUALITY_KEY = 'pipu.quality';
|
||||
const CLEAR_CACHE_KEY = 'pipu.cache.clear';
|
||||
const DEFAULT_QUALITY: QualityPrefs = { wifi: 'high', cellular: 'medium', download: 'high' };
|
||||
|
||||
let quality: QualityPrefs = DEFAULT_QUALITY;
|
||||
let loaded: Promise<void> | null = null;
|
||||
const listeners = new Set<() => void>();
|
||||
|
||||
export const qualityPrefs = {
|
||||
get: () => quality,
|
||||
subscribe(fn: () => void) {
|
||||
listeners.add(fn);
|
||||
return () => listeners.delete(fn);
|
||||
},
|
||||
async load(): Promise<QualityPrefs> {
|
||||
loaded ??= SecureStore.getItemAsync(QUALITY_KEY)
|
||||
.then((raw) => {
|
||||
if (raw) quality = { ...DEFAULT_QUALITY, ...(JSON.parse(raw) as Partial<QualityPrefs>) };
|
||||
})
|
||||
.catch(() => undefined);
|
||||
await loaded;
|
||||
return quality;
|
||||
},
|
||||
async set(patch: Partial<QualityPrefs>) {
|
||||
quality = { ...quality, ...patch };
|
||||
for (const fn of listeners) fn();
|
||||
await SecureStore.setItemAsync(QUALITY_KEY, JSON.stringify(quality));
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Кэш недавних стримов ExoPlayer (KotlinAudio кладёт его в `cacheDir/TrackPlayer`). Пока сервис плеера жив,
|
||||
* SimpleCache держит индекс в памяти — поэтому очистка откладывается до следующего холодного запуска.
|
||||
*/
|
||||
const PLAYER_CACHE = `${FileSystem.cacheDirectory}TrackPlayer`;
|
||||
|
||||
export const playerCache = {
|
||||
async size(): Promise<number> {
|
||||
const info = await FileSystem.getInfoAsync(PLAYER_CACHE, { size: true }).catch(() => null);
|
||||
return info?.exists ? (info.size ?? 0) : 0;
|
||||
},
|
||||
async requestClear() {
|
||||
await SecureStore.setItemAsync(CLEAR_CACHE_KEY, '1');
|
||||
},
|
||||
async clearPending(): Promise<boolean> {
|
||||
return (await SecureStore.getItemAsync(CLEAR_CACHE_KEY)) === '1';
|
||||
},
|
||||
/** Вызывается до setupPlayer, когда сервис ещё не запущен. */
|
||||
async clearIfRequested() {
|
||||
if (!(await this.clearPending())) return;
|
||||
await FileSystem.deleteAsync(PLAYER_CACHE, { idempotent: true }).catch(() => undefined);
|
||||
await SecureStore.deleteItemAsync(CLEAR_CACHE_KEY);
|
||||
},
|
||||
};
|
||||
Reference in new issue
Block a user