import * as SecureStore from 'expo-secure-store'; const URL_KEY = 'goon.backend_url'; const API_KEY = 'goon.api_key'; const DEVICE_KEY = 'goon.device_id'; // Stabilne ID instalacji — scope'uje stan usera (favorites/progress/blacklisty) na // serwerze per urządzenie (bug 2026-06-08: stan był globalny, nowi userzy nadpisywali // ulubione). Generowane raz, trzymane w SecureStore (przeżywa restart, NIE reinstalację). let _deviceIdCache: string | null = null; function _genDeviceId(): string { // 32 hex chars — wystarczająco unikalne dla ID instalacji (nie security-critical). let s = ''; for (let i = 0; i < 32; i++) s += Math.floor(Math.random() * 16).toString(16); return s; } export async function getDeviceId(): Promise { if (_deviceIdCache) return _deviceIdCache; let id = await SecureStore.getItemAsync(DEVICE_KEY); if (!id) { id = _genDeviceId(); await SecureStore.setItemAsync(DEVICE_KEY, id); } _deviceIdCache = id; return id; } // Jednorazowe przejęcie legacy stanu (sprzed device-scopingu) — flaga per instalacja. const LEGACY_ADOPTED_KEY = 'goon.legacy_adopted'; export async function isLegacyAdopted(): Promise { return (await SecureStore.getItemAsync(LEGACY_ADOPTED_KEY)) === '1'; } export async function markLegacyAdopted(): Promise { await SecureStore.setItemAsync(LEGACY_ADOPTED_KEY, '1'); } // "What's new" — ostatnio widziany wpis changelogu. Po dociągnięciu OTA bundle ma // nowszy changelog → WhatsNewModal pokazuje różnicę i zapisuje najnowszy id. const CHANGELOG_SEEN_KEY = 'goon.changelog_seen_id'; export async function getLastSeenChangelog(): Promise { return SecureStore.getItemAsync(CHANGELOG_SEEN_KEY); } export async function setLastSeenChangelog(id: string): Promise { await SecureStore.setItemAsync(CHANGELOG_SEEN_KEY, id); } // Liczba kolumn w siatkach scen (1/2/3). Feedback mobilism: domyślne 2 kol = za małe // miniaturki na telefonie do rozpoznania performera. Default 2 (tablet-friendly). const GRID_COLS_KEY = 'goon.grid_columns'; export async function getGridColumns(): Promise { const v = await SecureStore.getItemAsync(GRID_COLS_KEY); const n = v ? parseInt(v, 10) : 2; return n === 1 || n === 2 || n === 3 ? n : 2; } export async function setGridColumns(n: number): Promise { await SecureStore.setItemAsync(GRID_COLS_KEY, String(n)); } export interface Credentials { baseUrl: string; apiKey: string; } export async function loadCredentials(): Promise { const baseUrl = await SecureStore.getItemAsync(URL_KEY); const apiKey = await SecureStore.getItemAsync(API_KEY); if (!baseUrl || !apiKey) return null; return { baseUrl, apiKey }; } export async function saveCredentials(c: Credentials): Promise { await SecureStore.setItemAsync(URL_KEY, c.baseUrl); await SecureStore.setItemAsync(API_KEY, c.apiKey); } export async function clearCredentials(): Promise { await SecureStore.deleteItemAsync(URL_KEY); await SecureStore.deleteItemAsync(API_KEY); }