127 lines
3.6 KiB
Dart
127 lines
3.6 KiB
Dart
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);
|
|
}
|
|
}
|