2bcbb53c49
connectivityProvider — StreamProvider<bool>; true when any connectivity result is non-none. No Wi-Fi gate per operator decision. cacheSettingsProvider — AsyncNotifier<CacheSettings> persisting capBytes / prefetchWindow / cacheLikedTracks via flutter_secure_storage. Defaults: 5 GB cap, 5-track prefetch, cache liked = on. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
88 lines
2.8 KiB
Dart
88 lines
2.8 KiB
Dart
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
|
|
|
import '../auth/auth_provider.dart' show secureStorageProvider;
|
|
|
|
/// Operator-tunable cache settings (#357 plan B). Persisted via
|
|
/// flutter_secure_storage on the same device.
|
|
class CacheSettings {
|
|
const CacheSettings({
|
|
required this.capBytes,
|
|
required this.prefetchWindow,
|
|
required this.cacheLikedTracks,
|
|
});
|
|
|
|
/// 0 = unlimited.
|
|
final int capBytes;
|
|
|
|
/// 1..10. Number of next-tracks the prefetcher pre-downloads.
|
|
final int prefetchWindow;
|
|
|
|
/// When true, every like_track event triggers a pin with source autoLiked.
|
|
final bool cacheLikedTracks;
|
|
|
|
CacheSettings copyWith({
|
|
int? capBytes,
|
|
int? prefetchWindow,
|
|
bool? cacheLikedTracks,
|
|
}) =>
|
|
CacheSettings(
|
|
capBytes: capBytes ?? this.capBytes,
|
|
prefetchWindow: prefetchWindow ?? this.prefetchWindow,
|
|
cacheLikedTracks: cacheLikedTracks ?? this.cacheLikedTracks,
|
|
);
|
|
|
|
static const defaults = CacheSettings(
|
|
capBytes: 5 * 1024 * 1024 * 1024,
|
|
prefetchWindow: 5,
|
|
cacheLikedTracks: true,
|
|
);
|
|
}
|
|
|
|
class CacheSettingsController extends AsyncNotifier<CacheSettings> {
|
|
static const _kCap = 'cache_cap_bytes';
|
|
static const _kPrefetch = 'cache_prefetch_window';
|
|
static const _kCacheLiked = 'cache_liked_tracks';
|
|
|
|
late FlutterSecureStorage _storage;
|
|
|
|
@override
|
|
Future<CacheSettings> build() async {
|
|
_storage = ref.read(secureStorageProvider);
|
|
final cap = await _storage.read(key: _kCap);
|
|
final pre = await _storage.read(key: _kPrefetch);
|
|
final liked = await _storage.read(key: _kCacheLiked);
|
|
return CacheSettings(
|
|
capBytes: cap == null
|
|
? CacheSettings.defaults.capBytes
|
|
: int.tryParse(cap) ?? CacheSettings.defaults.capBytes,
|
|
prefetchWindow: pre == null
|
|
? CacheSettings.defaults.prefetchWindow
|
|
: (int.tryParse(pre) ?? 5).clamp(1, 10),
|
|
cacheLikedTracks: liked == null
|
|
? CacheSettings.defaults.cacheLikedTracks
|
|
: liked == 'true',
|
|
);
|
|
}
|
|
|
|
Future<void> setCapBytes(int bytes) async {
|
|
await _storage.write(key: _kCap, value: bytes.toString());
|
|
state = AsyncData(state.value!.copyWith(capBytes: bytes));
|
|
}
|
|
|
|
Future<void> setPrefetchWindow(int n) async {
|
|
final clamped = n.clamp(1, 10);
|
|
await _storage.write(key: _kPrefetch, value: clamped.toString());
|
|
state = AsyncData(state.value!.copyWith(prefetchWindow: clamped));
|
|
}
|
|
|
|
Future<void> setCacheLikedTracks(bool on) async {
|
|
await _storage.write(key: _kCacheLiked, value: on.toString());
|
|
state = AsyncData(state.value!.copyWith(cacheLikedTracks: on));
|
|
}
|
|
}
|
|
|
|
final cacheSettingsProvider =
|
|
AsyncNotifierProvider<CacheSettingsController, CacheSettings>(
|
|
CacheSettingsController.new);
|