feat: 长辈模式(大字大按钮 + 偏好按账号隔离)+ 语音输入(按住说话 + 实时转写 + 后端代理 DashScope ASR + 患者端专用)+ 健康仪表盘背景渐变

This commit is contained in:
MingNian
2026-07-21 10:53:16 +08:00
parent 0cb5b8e85a
commit 28f704c98e
25 changed files with 2214 additions and 131 deletions

View File

@@ -3,6 +3,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:shadcn_ui/shadcn_ui.dart';
import '../core/app_colors.dart';
import '../core/app_design_tokens.dart';
import '../core/elder_mode_scope.dart';
import '../core/app_module_visuals.dart';
import '../core/navigation_provider.dart';
import '../providers/auth_provider.dart';
@@ -307,11 +308,12 @@ class _MetricTile extends StatelessWidget {
@override
Widget build(BuildContext context) {
final elderMode = ElderModeScope.enabledOf(context);
return InkWell(
onTap: onTap,
borderRadius: BorderRadius.circular(18),
child: Container(
height: 100,
height: elderMode ? 112 : 100,
padding: const EdgeInsets.symmetric(horizontal: 5, vertical: 10),
decoration: BoxDecoration(
color: Colors.white.withValues(alpha: 0.22),
@@ -368,6 +370,7 @@ class _NavigationSection extends StatelessWidget {
@override
Widget build(BuildContext context) {
final elderMode = ElderModeScope.enabledOf(context);
final items = [
_NavItem(
icon: LucideIcons.folderHeart,
@@ -426,15 +429,19 @@ class _NavigationSection extends StatelessWidget {
itemCount: items.length,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 4,
mainAxisExtent: 82,
mainAxisSpacing: 7,
crossAxisSpacing: 8,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: elderMode ? 2 : 4,
mainAxisExtent: elderMode ? 82 : 82,
mainAxisSpacing: elderMode ? 10 : 7,
crossAxisSpacing: elderMode ? 10 : 8,
),
itemBuilder: (context, index) {
final item = items[index];
return _NavTile(item: item, onTap: () => pushRoute(ref, item.route));
return _NavTile(
item: item,
elderMode: elderMode,
onTap: () => pushRoute(ref, item.route),
);
},
),
);
@@ -443,8 +450,13 @@ class _NavigationSection extends StatelessWidget {
class _NavTile extends StatelessWidget {
final _NavItem item;
final bool elderMode;
final VoidCallback onTap;
const _NavTile({required this.item, required this.onTap});
const _NavTile({
required this.item,
required this.elderMode,
required this.onTap,
});
String get _title => switch (item.route) {
'healthArchive' => '健康档案',
@@ -473,6 +485,54 @@ class _NavTile extends StatelessWidget {
@override
Widget build(BuildContext context) {
final isDevice = item.route == 'devices';
if (elderMode) {
return InkWell(
onTap: onTap,
borderRadius: AppRadius.lgBorder,
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 10),
decoration: BoxDecoration(
color: const Color(0xFFF8F8FC),
borderRadius: AppRadius.lgBorder,
border: Border.all(color: const Color(0xFFE7E8F0)),
),
child: Row(
children: [
Container(
width: 54,
height: 54,
decoration: BoxDecoration(
color: isDevice ? AppColors.device : null,
gradient: isDevice
? null
: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: _colors,
),
borderRadius: AppRadius.mdBorder,
),
child: Icon(item.icon, color: Colors.white, size: 29),
),
const SizedBox(width: 10),
Expanded(
child: Text(
_title,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: const TextStyle(
fontSize: 17,
fontWeight: FontWeight.w700,
color: AppColors.textPrimary,
height: 1.15,
),
),
),
],
),
),
);
}
return InkWell(
onTap: onTap,
borderRadius: AppRadius.mdBorder,
@@ -635,23 +695,13 @@ class _HealthDashboardBackgroundPainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
final rect = Offset.zero & size;
canvas.drawRect(rect, Paint()..color = const Color(0xFFBAE6FD));
void drawGlow(Alignment center, Color color) {
final paint = Paint()
..shader = RadialGradient(
center: center,
radius: 1,
colors: [color, color.withValues(alpha: 0)],
stops: const [0, 0.8],
).createShader(rect);
canvas.drawRect(rect, paint);
}
drawGlow(Alignment.bottomRight, const Color(0xFF818CF8));
drawGlow(const Alignment(0, 0.6), const Color(0xFF60A5FA));
drawGlow(const Alignment(0.6, -0.6), const Color(0xFF6366F1));
drawGlow(const Alignment(-0.6, -0.6), const Color(0xFF38BDF8));
final paint = Paint()
..shader = const LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [Color(0xFF00C6FB), Color(0xFF005BEA)],
).createShader(rect);
canvas.drawRect(rect, paint);
}
@override