mirror of
https://gh-proxy.org/https://github.com/tiajinsha/JKVideo
synced 2026-07-07 23:18:38 +08:00
feat: 深色模式完善 + UP主主页 + 缓存管理
- 深色模式:补全 settings 页选项按钮、退出登录按钮主题色 - UP主主页:新增 /creator/[mid] 路由,展示 UP 主信息、粉丝数、视频列表 - bilibili.ts 新增 getUploaderInfo / getUploaderVideos API - 视频详情页 UP 主行可点击跳转主页 - 缓存管理:settings 页新增「存储」分区,显示缓存大小并支持一键清除 - 新增 utils/cache.ts(计算大小 + 清除 expo-image/文件系统缓存)
This commit is contained in:
63
utils/cache.ts
Normal file
63
utils/cache.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
import { Platform } from 'react-native';
|
||||
import * as FileSystem from 'expo-file-system/legacy';
|
||||
|
||||
/** Get total size (bytes) of a directory recursively */
|
||||
async function dirSize(dirUri: string): Promise<number> {
|
||||
try {
|
||||
const info = await FileSystem.getInfoAsync(dirUri);
|
||||
if (!info.exists) return 0;
|
||||
const entries = await FileSystem.readDirectoryAsync(dirUri);
|
||||
let total = 0;
|
||||
for (const entry of entries) {
|
||||
const entryUri = dirUri.endsWith('/') ? `${dirUri}${entry}` : `${dirUri}/${entry}`;
|
||||
const entryInfo = await FileSystem.getInfoAsync(entryUri, { size: true });
|
||||
if (!entryInfo.exists) continue;
|
||||
if (entryInfo.isDirectory) {
|
||||
total += await dirSize(entryUri);
|
||||
} else {
|
||||
total += (entryInfo as any).size ?? 0;
|
||||
}
|
||||
}
|
||||
return total;
|
||||
} catch {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/** Format bytes to human-readable string */
|
||||
export function formatBytes(bytes: number): string {
|
||||
if (bytes < 1024) return `${bytes} B`;
|
||||
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
||||
if (bytes < 1024 * 1024 * 1024) return `${(bytes / 1024 / 1024).toFixed(1)} MB`;
|
||||
return `${(bytes / 1024 / 1024 / 1024).toFixed(2)} GB`;
|
||||
}
|
||||
|
||||
/** Calculate image cache size (expo-image uses its own cache dirs) */
|
||||
export async function getImageCacheSize(): Promise<number> {
|
||||
if (Platform.OS === 'web') return 0;
|
||||
const cacheDir = FileSystem.cacheDirectory ?? '';
|
||||
return dirSize(cacheDir);
|
||||
}
|
||||
|
||||
/** Clear expo-image disk cache + expo-file-system cache directory */
|
||||
export async function clearImageCache(): Promise<void> {
|
||||
if (Platform.OS === 'web') return;
|
||||
try {
|
||||
const { Image } = require('expo-image');
|
||||
await Image.clearDiskCache();
|
||||
await Image.clearMemoryCache();
|
||||
} catch {}
|
||||
// Also clear the general cache directory (MPD files, QR codes, etc.)
|
||||
try {
|
||||
const cacheDir = FileSystem.cacheDirectory ?? '';
|
||||
const entries = await FileSystem.readDirectoryAsync(cacheDir);
|
||||
await Promise.all(
|
||||
entries.map(async entry => {
|
||||
const uri = `${cacheDir}${entry}`;
|
||||
try {
|
||||
await FileSystem.deleteAsync(uri, { idempotent: true });
|
||||
} catch {}
|
||||
})
|
||||
);
|
||||
} catch {}
|
||||
}
|
||||
32
utils/secureStorage.ts
Normal file
32
utils/secureStorage.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||
import { Platform } from 'react-native';
|
||||
|
||||
// expo-secure-store is only available on native platforms
|
||||
let SecureStore: typeof import('expo-secure-store') | null = null;
|
||||
if (Platform.OS !== 'web') {
|
||||
try { SecureStore = require('expo-secure-store'); } catch {}
|
||||
}
|
||||
|
||||
/** Read a sensitive value from SecureStore (native) or AsyncStorage (web fallback). */
|
||||
export async function getSecure(key: string): Promise<string | null> {
|
||||
if (SecureStore) {
|
||||
return SecureStore.getItemAsync(key);
|
||||
}
|
||||
return AsyncStorage.getItem(key);
|
||||
}
|
||||
|
||||
export async function setSecure(key: string, value: string): Promise<void> {
|
||||
if (SecureStore) {
|
||||
await SecureStore.setItemAsync(key, value);
|
||||
} else {
|
||||
await AsyncStorage.setItem(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
export async function deleteSecure(key: string): Promise<void> {
|
||||
if (SecureStore) {
|
||||
await SecureStore.deleteItemAsync(key);
|
||||
} else {
|
||||
await AsyncStorage.removeItem(key);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user