Initial commit

This commit is contained in:
admin1
2026-07-14 11:11:36 +08:00
commit 656499cf94
604 changed files with 119518 additions and 0 deletions
@@ -0,0 +1,126 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../../providers/trakt_scrobble_status_provider.dart';
import '../../../providers/trakt_settings_provider.dart';
import '../../../shared/widgets/app_inline_alert.dart';
import '../../../shared/widgets/app_loading_ring.dart';
import '../widgets/settings_card.dart';
class TraktSettingsTab extends ConsumerWidget {
final void Function(String message, {AppAlertTone tone}) onFeedback;
const TraktSettingsTab({super.key, required this.onFeedback});
@override
Widget build(BuildContext context, WidgetRef ref) {
final trakt = ref.watch(traktSettingsProvider);
return SettingsTabScroll(
children: [
trakt.when(
data: (data) => TraktSection(state: data, onFeedback: onFeedback),
loading: () => const Padding(
padding: EdgeInsets.symmetric(vertical: 32),
child: Center(child: AppLoadingRing()),
),
error: (e, _) => SettingsCard(children: [settingsLoadError(e)]),
),
],
);
}
}
class TraktSection extends ConsumerStatefulWidget {
final TraktState state;
final void Function(String message, {AppAlertTone tone}) onFeedback;
const TraktSection({
super.key,
required this.state,
required this.onFeedback,
});
@override
ConsumerState<TraktSection> createState() => TraktSectionState();
}
class TraktSectionState extends ConsumerState<TraktSection> {
bool _busy = false;
@override
Widget build(BuildContext context) {
final s = widget.state;
if (s.isConnected) {
return SettingsCard(
children: [
SettingRow(
title: '已连接',
subtitle: s.username.isEmpty ? 'Trakt 账号' : '@${s.username}',
trailing: const Icon(
Icons.check_circle,
size: 18,
color: Color(0xFF52C41A),
),
),
SettingRow(
title: '断开连接',
subtitle: '清除本地保存的 Trakt 令牌',
trailing: _busy
? const AppLoadingRing(size: 18)
: const Icon(Icons.logout, size: 18),
onTap: _busy ? null : _disconnect,
),
],
);
}
return SettingsCard(
children: [
SettingRow(
title: '连接 Trakt',
subtitle: '通过浏览器授权你的 Trakt 账号',
trailing: _busy
? const AppLoadingRing(size: 18)
: const Icon(Icons.open_in_new, size: 18),
onTap: _busy ? null : _connect,
),
],
);
}
Future<void> _connect() async {
setState(() => _busy = true);
String? message;
var tone = AppAlertTone.success;
try {
await ref.read(traktSettingsProvider.notifier).connect();
message = '已连接 Trakt';
unawaited(ref.read(traktScrobbleStatusProvider.notifier).retryPending());
} on TraktConnectException catch (e) {
message = e.message;
tone = AppAlertTone.error;
} catch (_) {
message = '连接失败';
tone = AppAlertTone.error;
}
if (!mounted) return;
setState(() => _busy = false);
_toast(message, tone: tone);
}
Future<void> _disconnect() async {
setState(() => _busy = true);
await ref.read(traktSettingsProvider.notifier).disconnect();
if (!mounted) return;
setState(() => _busy = false);
_toast('已断开 Trakt', tone: AppAlertTone.success);
}
void _toast(String message, {AppAlertTone tone = AppAlertTone.info}) {
widget.onFeedback(message, tone: tone);
}
}