ver1.00.00

update
This commit is contained in:
spasolreisa
2026-04-21 00:28:41 +08:00
parent b985cd1f9e
commit f5f62c828d
13 changed files with 1496 additions and 175 deletions

View File

@@ -1,31 +1,320 @@
import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
import 'dart:math';
import 'package:webview_flutter/webview_flutter.dart'; // 【你要的导入】
import '../providers/user_provider.dart';
class SettingPage extends StatelessWidget {
const SettingPage({super.key});
@override
Widget build(BuildContext context) {
final isDarkMode = Theme.of(context).brightness == Brightness.dark;
return Scaffold(
// 注意:这里不需要 bottomNavigationBar 了,因为外层已经有了
backgroundColor: Colors.transparent, // 关键:背景透明,透出玻璃效果
body: CustomScrollView(
slivers: [
SliverAppBar.large(
title: const Text('首页'),
floating: true,
backgroundColor: Colors.blueAccent.withOpacity(0.8),
backgroundColor: isDarkMode ? Colors.black : Colors.grey[50],
appBar: AppBar(
title: const Text(
"设置",
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w600,
),
SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) => ListTile(
title: Text('列表项 $index'),
leading: const Icon(Icons.article),
),
childCount: 20,
),
centerTitle: true,
backgroundColor: isDarkMode ? Colors.black : Colors.white,
elevation: 0,
foregroundColor: isDarkMode ? Colors.white : Colors.black87,
),
body: SingleChildScrollView(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
child: Column(
children: [
const SizedBox(height: 10),
const _SettingItem(
title: "缓存管理",
icon: Icons.storage_rounded,
hasSwitch: false,
showTrailingText: true,
),
const SizedBox(height: 12),
const _SettingItem(
title: "退出登录/清除账号",
icon: Icons.logout_rounded,
hasSwitch: false,
isLogout: true,
),
const SizedBox(height: 12),
const _SettingItem(
title: "隐私政策",
icon: Icons.privacy_tip_rounded,
hasSwitch: false,
),
const SizedBox(height: 12),
const _SettingItem(
title: "关于我们",
icon: Icons.info_outline_rounded,
hasSwitch: false,
),
const SizedBox(height: 30),
],
),
),
);
}
}
class _SettingItem extends StatefulWidget {
const _SettingItem({
required this.title,
required this.icon,
required this.hasSwitch,
this.showTrailingText = false,
this.isLogout = false,
});
final String title;
final IconData icon;
final bool hasSwitch;
final bool showTrailingText;
final bool isLogout;
@override
State<_SettingItem> createState() => _SettingItemState();
}
class _SettingItemState extends State<_SettingItem> {
String cacheSize = "计算中...";
@override
void initState() {
super.initState();
if (widget.showTrailingText) {
_getCacheSize();
}
}
Future<void> _getCacheSize() async {
try {
final cacheDir = await getTemporaryDirectory();
final imageCacheDir = Directory("${cacheDir.path}/image_cache");
if (await imageCacheDir.exists()) {
int totalBytes = 0;
await for (var file in imageCacheDir.list(recursive: true)) {
if (file is File) {
totalBytes += await file.length();
}
}
cacheSize = _formatBytes(totalBytes);
} else {
cacheSize = "0 B";
}
} catch (e) {
cacheSize = "获取失败";
}
if (mounted) setState(() {});
}
Future<void> _clearCache() async {
try {
final cacheDir = await getTemporaryDirectory();
final imageCacheDir = Directory("${cacheDir.path}/image_cache");
if (await imageCacheDir.exists()) {
await imageCacheDir.delete(recursive: true);
}
setState(() {
cacheSize = "0 B";
});
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("✅ 缓存已清空")),
);
}
} catch (e) {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("❌ 清空缓存失败")),
);
}
}
}
void _showClearCacheConfirm() {
showCupertinoDialog(
context: context,
builder: (context) => CupertinoAlertDialog(
title: const Text("确定清空缓存?"),
content: const Text("清空后将重新加载图片等数据,无法恢复"),
actions: [
CupertinoDialogAction(
child: const Text("取消"),
onPressed: () => Navigator.pop(context),
),
CupertinoDialogAction(
child: const Text("确定清空"),
onPressed: () async {
Navigator.pop(context);
await _clearCache();
},
),
],
),
);
}
Future<void> _deleteAccount() async {
showCupertinoDialog(
context: context,
builder: (context) => CupertinoAlertDialog(
title: const Text("确定退出登录?"),
content: const Text("将清除本地账号信息,需重新登录"),
actions: [
CupertinoDialogAction(
child: const Text("取消"),
onPressed: () => Navigator.pop(context),
),
CupertinoDialogAction(
child: const Text("确定退出"),
onPressed: () async {
Navigator.pop(context);
await UserProvider.instance.logout();
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("✅ 已退出登录,账号已清除")),
);
}
},
),
],
),
);
}
// ================== 打开 WebView 页面 ==================
void _openWebView(String title, String url) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Scaffold(
appBar: AppBar(title: Text(title)),
body: WebViewWidget(
controller: WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted)
..loadRequest(Uri.parse(url)),
),
),
),
);
}
String _formatBytes(int bytes) {
if (bytes <= 0) return "0 B";
const suffixes = ["B", "KB", "MB", "GB"];
var i = (log(bytes) / log(1024)).floor();
return '${(bytes / pow(1024, i)).toStringAsFixed(2)} ${suffixes[i]}';
}
@override
Widget build(BuildContext context) {
final isDarkMode = Theme.of(context).brightness == Brightness.dark;
return GestureDetector(
onTap: () {
if (widget.showTrailingText) {
_showClearCacheConfirm();
} else if (widget.isLogout) {
_deleteAccount();
} else if (widget.title == "隐私政策") {
_openWebView("隐私政策", "https://union.godserver.cn/document");
} else if (widget.title == "关于我们") {
_openWebView("关于我们", "https://union.godserver.cn/thank");
}
},
child: Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(horizontal: 18, vertical: 16),
decoration: BoxDecoration(
color: isDarkMode ? Colors.grey[900] : Colors.white,
borderRadius: BorderRadius.circular(12),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Icon(
widget.icon,
color: isDarkMode ? Colors.white : Colors.black87,
size: 22,
),
const SizedBox(width: 14),
Text(
widget.title,
style: TextStyle(
color: isDarkMode ? Colors.white : Colors.black87,
fontSize: 16,
fontWeight: FontWeight.w500,
),
),
],
),
widget.hasSwitch
? const _SimpleSwitch()
: widget.showTrailingText
? Text(
cacheSize,
style: TextStyle(
color: isDarkMode ? Colors.white54 : Colors.black54,
fontSize: 14,
),
)
: widget.isLogout
? const SizedBox()
: Icon(
Icons.arrow_forward_ios_rounded,
color: isDarkMode ? Colors.white54 : Colors.black54,
size: 16,
),
],
),
),
);
}
}
class _SimpleSwitch extends StatefulWidget {
const _SimpleSwitch();
@override
State<_SimpleSwitch> createState() => _SimpleSwitchState();
}
class _SimpleSwitchState extends State<_SimpleSwitch> {
bool isEnabled = true;
@override
Widget build(BuildContext context) {
final isDarkMode = Theme.of(context).brightness == Brightness.dark;
return CupertinoSwitch(
value: isEnabled,
onChanged: (val) {
setState(() => isEnabled = val);
},
activeColor: isDarkMode ? Colors.white : Colors.blueAccent,
trackColor: isDarkMode ? Colors.white38 : Colors.grey[300],
thumbColor: isDarkMode ? Colors.white : Colors.white,
);
}
}