feat(flutter): 增加 debug 运行时服务器地址设置

This commit is contained in:
Zhou Weidong committed 2026-10-17 22:54:07 +08:00
1 parent b76228905c
commit 907562a874
14 files changed
+590 -27

No files matched your search

+162 -19
View File
@@ -1,12 +1,16 @@
// Author: fruit.com.cn
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../../core/config/app_config.dart';
import '../../core/config/locale_controller.dart';
import '../../core/config/server_endpoint.dart';
import '../../core/data/models/drama.dart';
import '../../core/data/models/watch_progress.dart';
import '../../core/data/repositories/watch_history_repository.dart';
import '../../core/theme/app_colors.dart';
import '../../l10n/app_localizations.dart';
enum MyPageAction { home, discover, resume }
@@ -110,39 +114,178 @@ class MineLogic extends ChangeNotifier {
}
}
Future<void> showLanguage(BuildContext context) async {
Future<void> showLanguage(
BuildContext context, {
bool showServerSetting = kDebugMode,
}) async {
final l10n = AppLocalizations.of(context)!;
await showModalBottomSheet<void>(
context: context,
backgroundColor: const Color(0xFF1C1D22),
showDragHandle: true,
isScrollControlled: true,
builder: (sheetContext) => SafeArea(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
ListTile(title: Text(l10n.language)),
for (final (code, label) in [
('en', l10n.english),
('zh', l10n.simplifiedChinese),
('id', l10n.bahasaIndonesia),
])
ListTile(
title: Text(label),
onTap: () {
context.read<LocaleController>().select(code);
Navigator.pop(sheetContext);
},
),
const SizedBox(height: 8),
],
child: ConstrainedBox(
constraints: BoxConstraints(
maxHeight: MediaQuery.sizeOf(sheetContext).height * 0.85,
),
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
ListTile(title: Text(l10n.language)),
for (final (code, label) in [
('en', l10n.english),
('zh', l10n.simplifiedChinese),
('id', l10n.bahasaIndonesia),
])
ListTile(
title: Text(label),
onTap: () {
context.read<LocaleController>().select(code);
Navigator.pop(sheetContext);
},
),
if (showServerSetting) ...[
const Divider(height: 1),
ListTile(
key: const Key('server-endpoint-setting'),
leading: const Icon(Icons.dns_outlined),
title: Text(l10n.serverAddress),
subtitle: Text(AppConfig.apiBaseUrl),
trailing: const Icon(Icons.edit_outlined),
onTap: () => _editServerEndpoint(context, l10n),
),
],
const SizedBox(height: 8),
],
),
),
),
),
);
}
Future<void> _editServerEndpoint(
BuildContext context,
AppLocalizations l10n,
) async {
final changed = await showDialog<bool>(
context: context,
builder: (_) => _ServerEndpointDialog(l10n: l10n),
);
if (changed == true && context.mounted) {
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text(l10n.restartToApply)));
}
}
@override
void dispose() {
_disposed = true;
super.dispose();
}
}
class _ServerEndpointDialog extends StatefulWidget {
const _ServerEndpointDialog({required this.l10n});
final AppLocalizations l10n;
@override
State<_ServerEndpointDialog> createState() => _ServerEndpointDialogState();
}
class _ServerEndpointDialogState extends State<_ServerEndpointDialog> {
late final TextEditingController _controller = TextEditingController(
text: AppConfig.apiBaseUrl,
);
String? _error;
bool _saving = false;
@override
void dispose() {
_controller.dispose();
super.dispose();
}
Future<void> _save() async {
final normalized = ServerEndpoint.normalize(_controller.text);
if (normalized == null) {
setState(() => _error = widget.l10n.invalidServerAddress);
return;
}
setState(() {
_saving = true;
_error = null;
});
final saved = await ServerEndpoint.save(normalized);
if (!mounted) return;
if (!saved) {
setState(() {
_saving = false;
_error = widget.l10n.invalidServerAddress;
});
return;
}
Navigator.pop(context, true);
}
Future<void> _restoreDefault() async {
setState(() => _saving = true);
await ServerEndpoint.clear();
if (mounted) Navigator.pop(context, true);
}
@override
Widget build(BuildContext context) {
final l10n = widget.l10n;
return AlertDialog(
title: Text(l10n.serverAddress),
content: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextField(
key: const Key('server-endpoint-input'),
controller: _controller,
enabled: !_saving,
keyboardType: TextInputType.url,
autocorrect: false,
decoration: InputDecoration(
hintText: l10n.serverAddressHint,
errorText: _error,
errorMaxLines: 2,
),
),
const SizedBox(height: 10),
Text(
l10n.restartToApply,
key: const Key('server-endpoint-restart-hint'),
style: const TextStyle(color: AppColors.muted, fontSize: 12),
),
const SizedBox(height: 4),
TextButton(
key: const Key('server-endpoint-restore'),
onPressed: _saving ? null : _restoreDefault,
child: Text(l10n.restoreDefault),
),
],
),
),
actions: [
TextButton(
onPressed: _saving ? null : () => Navigator.pop(context, false),
child: Text(l10n.cancel),
),
FilledButton(
key: const Key('server-endpoint-save'),
onPressed: _saving ? null : _save,
child: Text(l10n.saveAddress),
),
],
);
}
}
+11 -2
View File
@@ -2,6 +2,7 @@
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
@@ -41,6 +42,7 @@ class MyPage extends StatefulWidget {
this.onSignOut,
this.dramas,
this.onDramaSelected,
this.debugShowSetting = kDebugMode,
});
final Drama drama;
@@ -57,6 +59,7 @@ class MyPage extends StatefulWidget {
final VoidCallback? onSignOut;
final List<Drama>? dramas;
final ValueChanged<Drama>? onDramaSelected;
final bool debugShowSetting;
@override
State<MyPage> createState() => _MyPageState();
@@ -214,7 +217,10 @@ class _MyPageState extends State<MyPage> {
leading: const Icon(Icons.language_rounded, color: AppColors.blueSoft),
title: Text(l10n.appLanguage),
trailing: const Icon(Icons.chevron_right_rounded),
onTap: () => logic.showLanguage(context),
onTap: () => logic.showLanguage(
context,
showServerSetting: widget.debugShowSetting,
),
),
];
@@ -471,7 +477,10 @@ class _MyPageState extends State<MyPage> {
),
title: Text(l10n.settings),
trailing: const Icon(Icons.chevron_right_rounded),
onTap: () => logic.showLanguage(context),
onTap: () => logic.showLanguage(
context,
showServerSetting: widget.debugShowSetting,
),
),
],
),