feat(ui): 登录页重设计并统一弹框主题渐变外壳

This commit is contained in:
Vicky authored and trae-solo-agent committed 2026-10-28 16:36:43 +08:00
1 parent c027acc91f
commit de7da64886
25 files changed
+905 -317

No files matched your search

+119
View File
@@ -0,0 +1,119 @@
// Author: fruit.com.cn
import 'package:flutter/material.dart';
import '../theme/app_colors.dart';
import '../theme/app_dimens.dart';
/// 主题红晕渐变容器:弹框(居中)与底部弹层(半屏)共用的外壳。
/// 纯黑弹框统一升级为「顶部红光 → 近黑」的家族渐变。
class AppGlowPanel extends StatelessWidget {
const AppGlowPanel({
super.key,
required this.child,
this.borderRadius = const BorderRadius.all(Radius.circular(20)),
this.border = true,
});
final Widget child;
final BorderRadius borderRadius;
final bool border;
static const _gradient = LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
AppColors.followingGlow,
AppColors.followingGlowMid,
Color(0xFF101012),
],
stops: [0, 0.22, 0.62],
);
@override
Widget build(BuildContext context) {
return DecoratedBox(
decoration: BoxDecoration(
gradient: _gradient,
borderRadius: borderRadius,
border: border
? Border.all(color: AppColors.contentBorder)
: null,
),
child: child,
);
}
}
/// 主题渐变确认弹框:替代 AlertDialog 的家族化外壳。
/// 按钮沿用项目惯例:纯文字 TextButton,主操作品牌红。
class AppGlowDialog extends StatelessWidget {
const AppGlowDialog({
super.key,
this.title,
this.content,
this.contentChild,
this.actions,
this.contentTextStyle,
});
final String? title;
final String? content;
/// 富内容(表单/滚动区),与 [content] 二选一。
final Widget? contentChild;
final List<Widget>? actions;
final TextStyle? contentTextStyle;
@override
Widget build(BuildContext context) {
final bodyStyle = contentTextStyle ??
TextStyle(
color: AppColors.muted,
fontSize: AppDimens.body,
fontWeight: FontWeight.w400,
);
return Dialog(
backgroundColor: AppColors.transparent,
elevation: 0,
child: AppGlowPanel(
child: Padding(
padding: const EdgeInsets.fromLTRB(22, 22, 22, 10),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (title != null) ...[
Text(
title!,
style: TextStyle(
color: AppColors.onSurface,
fontSize: AppDimens.sectionTitle,
fontWeight: FontWeight.w400,
),
),
const SizedBox(height: 14),
],
if (content != null)
Text(content!, style: bodyStyle)
else
?contentChild,
if (actions != null && actions!.isNotEmpty) ...[
const SizedBox(height: 18),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
for (var i = 0; i < actions!.length; i++) ...[
if (i > 0) const SizedBox(width: 4),
actions![i],
],
],
),
],
],
),
),
),
);
}
}
+7 -5
View File
@@ -5,6 +5,7 @@ import '../../l10n/app_localizations.dart';
import '../../pages/auth/auth_view.dart';
import '../data/services/auth_controller.dart';
import '../theme/app_colors.dart';
import 'app_glow_panel.dart';
/// 打开登录 / 注册页(沿用现有 Navigator 风格,不引路由库)
Future<void> openAuthPage(BuildContext context, {bool signUpMode = false}) {
@@ -23,11 +24,11 @@ Future<bool> ensureSignedIn(BuildContext context) async {
final l10n = AppLocalizations.of(context)!;
final go = await showModalBottomSheet<bool>(
context: context,
backgroundColor: AppColors.card,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(18)),
),
builder: (sheetContext) => SafeArea(
backgroundColor: AppColors.transparent,
builder: (sheetContext) => AppGlowPanel(
borderRadius: const BorderRadius.vertical(top: Radius.circular(18)),
border: false,
child: SafeArea(
child: Padding(
padding: const EdgeInsets.fromLTRB(20, 18, 20, 20),
child: Column(
@@ -71,6 +72,7 @@ Future<bool> ensureSignedIn(BuildContext context) async {
],
),
),
),
),
);
@@ -6,6 +6,7 @@ import 'package:flutter/material.dart';
import '../config/app_config.dart';
import '../config/server_endpoint.dart';
import '../theme/app_colors.dart';
import 'app_glow_panel.dart';
const String _title = '设置服务地址';
const String _save = '保存';
@@ -72,9 +73,9 @@ class _CatalogEndpointDialogState extends State<_CatalogEndpointDialog> {
@override
Widget build(BuildContext context) {
return AlertDialog(
title: const Text(_title),
content: SingleChildScrollView(
return AppGlowDialog(
title: _title,
contentChild: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,