feat: 长辈模式(大字大按钮 + 偏好按账号隔离)+ 语音输入(按住说话 + 实时转写 + 后端代理 DashScope ASR + 患者端专用)+ 健康仪表盘背景渐变
This commit is contained in:
@@ -9,7 +9,7 @@ const String baseUrl = String.fromEnvironment(
|
||||
'API_BASE_URL',
|
||||
defaultValue: kReleaseMode
|
||||
? 'https://erpapi.datalumina.cn/xiaomai'
|
||||
: 'http://192.168.1.34:5000',
|
||||
: 'http://10.4.178.175:5000',
|
||||
);
|
||||
|
||||
class ApiException implements Exception {
|
||||
|
||||
@@ -11,6 +11,7 @@ import '../pages/report/report_pages.dart';
|
||||
import '../pages/report/ai_analysis_page.dart';
|
||||
import '../pages/consultation/consultation_pages.dart';
|
||||
import '../pages/settings/settings_pages.dart';
|
||||
import '../pages/settings/elder_mode_page.dart';
|
||||
import '../pages/settings/notification_prefs_page.dart';
|
||||
import '../pages/notifications/notification_center_page.dart';
|
||||
import '../pages/history/conversation_history_page.dart';
|
||||
@@ -127,6 +128,8 @@ Widget buildPage(RouteInfo route, WidgetRef ref) {
|
||||
return const FollowUpListPage();
|
||||
case 'settings':
|
||||
return const SettingsPage();
|
||||
case 'elderMode':
|
||||
return const ElderModePage();
|
||||
case 'notificationPrefs':
|
||||
return const NotificationPrefsPage();
|
||||
case 'notifications':
|
||||
|
||||
@@ -776,6 +776,74 @@ class AppTheme {
|
||||
),
|
||||
);
|
||||
|
||||
/// 长辈模式只在已登录的患者端启用。这里提高主题级控件尺寸,页面中写死的
|
||||
/// 字号再由 ElderModeScope 提供的文本缩放统一兜底。
|
||||
static ThemeData get elderLightTheme {
|
||||
final base = lightTheme;
|
||||
return base.copyWith(
|
||||
appBarTheme: base.appBarTheme.copyWith(
|
||||
toolbarHeight: 60,
|
||||
titleTextStyle: const TextStyle(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: text,
|
||||
),
|
||||
iconTheme: const IconThemeData(size: 28, color: text),
|
||||
),
|
||||
textTheme: base.textTheme.copyWith(
|
||||
headlineLarge: const TextStyle(
|
||||
fontSize: 28,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: text,
|
||||
),
|
||||
titleLarge: const TextStyle(
|
||||
fontSize: 22,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: text,
|
||||
),
|
||||
titleMedium: const TextStyle(
|
||||
fontSize: 19,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: text,
|
||||
),
|
||||
bodyLarge: const TextStyle(fontSize: 18, color: text, height: 1.5),
|
||||
bodyMedium: const TextStyle(fontSize: 16, color: textSub, height: 1.45),
|
||||
labelMedium: const TextStyle(fontSize: 16, color: textSub),
|
||||
labelSmall: const TextStyle(fontSize: 15, color: textHint),
|
||||
),
|
||||
inputDecorationTheme: base.inputDecorationTheme.copyWith(
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
horizontal: 18,
|
||||
vertical: 16,
|
||||
),
|
||||
hintStyle: const TextStyle(color: textHint, fontSize: 17),
|
||||
),
|
||||
elevatedButtonTheme: ElevatedButtonThemeData(
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: primary,
|
||||
foregroundColor: Colors.white,
|
||||
minimumSize: const Size(double.infinity, 56),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(rLg),
|
||||
),
|
||||
textStyle: const TextStyle(fontSize: 18, fontWeight: FontWeight.w700),
|
||||
elevation: 0,
|
||||
),
|
||||
),
|
||||
outlinedButtonTheme: OutlinedButtonThemeData(
|
||||
style: OutlinedButton.styleFrom(
|
||||
foregroundColor: text,
|
||||
minimumSize: const Size(52, 56),
|
||||
side: const BorderSide(color: border),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(rMd),
|
||||
),
|
||||
textStyle: const TextStyle(fontSize: 18, fontWeight: FontWeight.w700),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
static ShadThemeData get shadTheme => ShadThemeData(
|
||||
brightness: Brightness.light,
|
||||
colorScheme: ShadVioletColorScheme.light(
|
||||
|
||||
42
health_app/lib/core/elder_mode_scope.dart
Normal file
42
health_app/lib/core/elder_mode_scope.dart
Normal file
@@ -0,0 +1,42 @@
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class ElderModeScope extends InheritedWidget {
|
||||
final bool enabled;
|
||||
final bool largeTextEnabled;
|
||||
|
||||
const ElderModeScope({
|
||||
super.key,
|
||||
required this.enabled,
|
||||
required this.largeTextEnabled,
|
||||
required super.child,
|
||||
});
|
||||
|
||||
static ElderModeScope? maybeOf(BuildContext context) {
|
||||
return context.dependOnInheritedWidgetOfExactType<ElderModeScope>();
|
||||
}
|
||||
|
||||
static bool enabledOf(BuildContext context) {
|
||||
return maybeOf(context)?.enabled == true;
|
||||
}
|
||||
|
||||
static bool largeTextOf(BuildContext context) {
|
||||
final scope = maybeOf(context);
|
||||
return scope?.enabled == true && scope?.largeTextEnabled == true;
|
||||
}
|
||||
|
||||
static TextScaler textScalerFor(BuildContext context) {
|
||||
final systemScaler = MediaQuery.textScalerOf(context);
|
||||
if (!largeTextOf(context)) return systemScaler;
|
||||
final systemFactor = systemScaler.scale(1);
|
||||
final factor = math.max(systemFactor, 1.18).clamp(1.0, 1.6).toDouble();
|
||||
return TextScaler.linear(factor);
|
||||
}
|
||||
|
||||
@override
|
||||
bool updateShouldNotify(ElderModeScope oldWidget) {
|
||||
return enabled != oldWidget.enabled ||
|
||||
largeTextEnabled != oldWidget.largeTextEnabled;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user