Files

189 lines
5.6 KiB
Dart
Raw Permalink Normal View History

2026-07-14 11:11:36 +08:00
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'shared/settings_persistence.dart';
enum TmdbAuthMode { bearer, apiKey }
enum TmdbAccessMode {
official,
smAccount,
}
class TmdbSettingsState {
static const officialApiBaseUrl = 'https://api.themoviedb.org/3';
static const officialImageBaseUrl = 'https://image.tmdb.org/t/p';
static const smAccountApiBaseUrl = 'https://your-server.example';
final bool enabled;
final TmdbAccessMode accessMode;
final TmdbAuthMode authMode;
final String accessToken;
final String apiKey;
final String language;
const TmdbSettingsState({
this.enabled = false,
this.accessMode = TmdbAccessMode.official,
this.authMode = TmdbAuthMode.apiKey,
this.accessToken = '',
this.apiKey = '',
this.language = 'zh-CN',
});
bool get isConfigured => switch (accessMode) {
TmdbAccessMode.smAccount => true,
TmdbAccessMode.official => switch (authMode) {
TmdbAuthMode.bearer => accessToken.isNotEmpty,
TmdbAuthMode.apiKey => apiKey.isNotEmpty,
},
};
bool get canRequest => enabled && isConfigured;
bool canRequestWithAccount({required bool dataPlaneReady}) =>
switch (accessMode) {
TmdbAccessMode.official => canRequest,
TmdbAccessMode.smAccount => enabled && dataPlaneReady,
};
String get effectiveApiBaseUrl => switch (accessMode) {
TmdbAccessMode.smAccount => smAccountApiBaseUrl,
TmdbAccessMode.official => officialApiBaseUrl,
};
String get effectiveImageBaseUrl => officialImageBaseUrl;
String get effectiveAccessToken =>
accessMode == TmdbAccessMode.official && authMode == TmdbAuthMode.bearer
? accessToken
: '';
String get effectiveApiKey =>
accessMode == TmdbAccessMode.official && authMode == TmdbAuthMode.apiKey
? apiKey
: '';
TmdbSettingsState copyWith({
bool? enabled,
TmdbAccessMode? accessMode,
TmdbAuthMode? authMode,
String? accessToken,
String? apiKey,
String? language,
}) => TmdbSettingsState(
enabled: enabled ?? this.enabled,
accessMode: accessMode ?? this.accessMode,
authMode: authMode ?? this.authMode,
accessToken: accessToken ?? this.accessToken,
apiKey: apiKey ?? this.apiKey,
language: language ?? this.language,
);
}
class TmdbSettingsNotifier extends AsyncNotifier<TmdbSettingsState>
with SettingsPersistence {
static const _keyEnabled = 'smplayer.tmdb_enabled';
static const _keyAccessMode = 'smplayer.tmdb_access_mode';
static const _keyAuthMode = 'smplayer.tmdb_auth_mode';
static const _keyAccessToken = 'smplayer.tmdb_access_token';
static const _keyApiKey = 'smplayer.tmdb_api_key';
static const _keyLanguage = 'smplayer.tmdb_language';
@override
Future<TmdbSettingsState> build() async {
final prefs = await getPrefs();
final accessToken = prefs.getString(_keyAccessToken)?.trim() ?? '';
final apiKey = prefs.getString(_keyApiKey)?.trim() ?? '';
return TmdbSettingsState(
enabled: prefs.getBool(_keyEnabled) ?? false,
accessMode: _parseAccessMode(prefs.getString(_keyAccessMode)),
authMode: _parseAuthMode(
prefs.getString(_keyAuthMode),
hasLegacyAccessToken: accessToken.isNotEmpty,
),
accessToken: accessToken,
apiKey: apiKey,
language: prefs.getString(_keyLanguage) ?? 'zh-CN',
);
}
Future<void> setEnabled(bool v) async {
final current = state.value ?? const TmdbSettingsState();
state = AsyncValue.data(current.copyWith(enabled: v));
await persistField(_keyEnabled, v);
}
Future<void> setAccessMode(TmdbAccessMode mode) async {
final current = state.value ?? const TmdbSettingsState();
state = AsyncValue.data(current.copyWith(accessMode: mode));
await persistField(_keyAccessMode, mode.name);
}
Future<void> enableSmAccountProxy() async {
final current = state.value ?? await future;
state = AsyncValue.data(
current.copyWith(enabled: true, accessMode: TmdbAccessMode.smAccount),
);
await persistFields(<String, dynamic>{
_keyEnabled: true,
_keyAccessMode: TmdbAccessMode.smAccount.name,
});
}
Future<void> setAuthMode(TmdbAuthMode mode) async {
final current = state.value ?? const TmdbSettingsState();
state = AsyncValue.data(current.copyWith(authMode: mode));
await persistField(_keyAuthMode, mode.name);
}
Future<void> setAccessToken(String token) async {
final trimmed = token.trim();
final current = state.value ?? const TmdbSettingsState();
state = AsyncValue.data(current.copyWith(accessToken: trimmed));
await persistField(_keyAccessToken, trimmed);
}
Future<void> setApiKey(String key) async {
final trimmed = key.trim();
final current = state.value ?? const TmdbSettingsState();
state = AsyncValue.data(current.copyWith(apiKey: trimmed));
await persistField(_keyApiKey, trimmed);
}
Future<void> setLanguage(String lang) async {
final current = state.value ?? const TmdbSettingsState();
state = AsyncValue.data(current.copyWith(language: lang));
await persistField(_keyLanguage, lang);
}
}
final tmdbSettingsProvider =
AsyncNotifierProvider<TmdbSettingsNotifier, TmdbSettingsState>(
TmdbSettingsNotifier.new,
);
TmdbAccessMode _parseAccessMode(String? value) => TmdbAccessMode.values
.firstWhere((m) => m.name == value, orElse: () => TmdbAccessMode.official);
TmdbAuthMode _parseAuthMode(
String? value, {
bool hasLegacyAccessToken = false,
}) {
if (value == null && hasLegacyAccessToken) {
return TmdbAuthMode.bearer;
}
return TmdbAuthMode.values.firstWhere(
(mode) => mode.name == value,
orElse: () => TmdbAuthMode.apiKey,
);
}