- 抽出 lib/core 的日期/JSON 工具,收敛各页重复解析 - 主页与音乐风险页拆成组件,风险功能共用一套运行框架 - 修复设置页作为主页页签保存时弹掉根路由导致的黑屏 - 登录对齐 Astral aimedb 协议:84 位二维码校验、签名与请求头修正, 补 GlobalSign 中间证书;Windows 改用 WinHTTP 绕过服务端对 BoringSSL 的 TLS 指纹拦截(证书校验保持开启) - 补开发预览数据与测试
137 lines
3.5 KiB
Dart
137 lines
3.5 KiB
Dart
import 'package:flutter/material.dart';
|
||
|
||
import '../config/strings.dart';
|
||
|
||
/// 全站统一的卡片外壳:无阴影、16 圆角、outline 描边。
|
||
///
|
||
/// 之前每个页面各写一份 `Card(elevation: 0, shape: RoundedRectangleBorder(...))`,
|
||
/// 改一处圆角/描边要改十几个文件。
|
||
class AppCard extends StatelessWidget {
|
||
final Widget child;
|
||
final EdgeInsetsGeometry padding;
|
||
final Color? borderColor;
|
||
final EdgeInsetsGeometry? margin;
|
||
final VoidCallback? onTap;
|
||
|
||
const AppCard({
|
||
super.key,
|
||
required this.child,
|
||
this.padding = const EdgeInsets.all(20),
|
||
this.borderColor,
|
||
this.margin,
|
||
this.onTap,
|
||
});
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
final theme = Theme.of(context);
|
||
final content = Padding(padding: padding, child: child);
|
||
|
||
return Card(
|
||
elevation: 0,
|
||
margin: margin,
|
||
shape: RoundedRectangleBorder(
|
||
borderRadius: BorderRadius.circular(16),
|
||
side: BorderSide(
|
||
color: borderColor ??
|
||
theme.colorScheme.outline.withValues(alpha: 0.3),
|
||
),
|
||
),
|
||
child: onTap == null
|
||
? content
|
||
: InkWell(
|
||
borderRadius: BorderRadius.circular(16),
|
||
onTap: onTap,
|
||
child: content,
|
||
),
|
||
);
|
||
}
|
||
}
|
||
|
||
/// 卡片内的标题行:图标 + 彩色标题。
|
||
class SectionTitle extends StatelessWidget {
|
||
final IconData icon;
|
||
final String title;
|
||
final Color? color;
|
||
final double iconSize;
|
||
|
||
const SectionTitle({
|
||
super.key,
|
||
required this.icon,
|
||
required this.title,
|
||
this.color,
|
||
this.iconSize = 18,
|
||
});
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
final theme = Theme.of(context);
|
||
final tint = color ?? theme.colorScheme.primary;
|
||
return Row(
|
||
children: [
|
||
Icon(icon, size: iconSize, color: tint),
|
||
const SizedBox(width: 8),
|
||
Expanded(
|
||
child: Text(
|
||
title,
|
||
style: theme.textTheme.labelLarge?.copyWith(
|
||
color: tint,
|
||
fontWeight: FontWeight.w600,
|
||
),
|
||
),
|
||
),
|
||
],
|
||
);
|
||
}
|
||
}
|
||
|
||
/// 「完成后自动退出登录并返回标题页」勾选框。
|
||
///
|
||
/// 六个功能页原本各抄一份 `InkWell + Checkbox + Text`,现在统一成一个卡片。
|
||
class AutoLogoutToggle extends StatelessWidget {
|
||
final bool value;
|
||
final bool enabled;
|
||
final ValueChanged<bool>? onChanged;
|
||
final String label;
|
||
|
||
const AutoLogoutToggle({
|
||
super.key,
|
||
required this.value,
|
||
required this.enabled,
|
||
required this.onChanged,
|
||
this.label = AppStrings.autoLogoutAndExit,
|
||
});
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
final theme = Theme.of(context);
|
||
return AppCard(
|
||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4),
|
||
child: InkWell(
|
||
borderRadius: BorderRadius.circular(16),
|
||
onTap: enabled ? () => onChanged?.call(!value) : null,
|
||
child: Row(
|
||
children: [
|
||
Checkbox(
|
||
value: value,
|
||
onChanged:
|
||
enabled ? (v) => onChanged?.call(v ?? false) : null,
|
||
),
|
||
Expanded(
|
||
child: Text(
|
||
label,
|
||
style: theme.textTheme.bodyMedium?.copyWith(
|
||
color: enabled
|
||
? null
|
||
: theme.colorScheme.onSurfaceVariant
|
||
.withValues(alpha: 0.6),
|
||
),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
);
|
||
}
|
||
}
|