189 lines
5.6 KiB
Dart
189 lines
5.6 KiB
Dart
|
|
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,
|
||
|
|
);
|
||
|
|
}
|