Commit 8d5a6c657725cc0b815b3364d18c97a5bba5977f

Authored by 常守达
1 parent ee15cd75

fix(today):说明弹窗

  1 +import 'package:doublefeel_flutter/app/modules/home/widgets/today/realtime_stress_explanation_bottom_sheet.dart';
1 import 'package:doublefeel_flutter/core/theme/app_theme.dart'; 2 import 'package:doublefeel_flutter/core/theme/app_theme.dart';
2 import 'package:doublefeel_flutter/l10n/l10n_extensions.dart'; 3 import 'package:doublefeel_flutter/l10n/l10n_extensions.dart';
3 import 'package:flutter/material.dart'; 4 import 'package:flutter/material.dart';
@@ -279,7 +280,9 @@ class _FaqLink extends StatelessWidget { @@ -279,7 +280,9 @@ class _FaqLink extends StatelessWidget {
279 Widget build(BuildContext context) { 280 Widget build(BuildContext context) {
280 return GestureDetector( 281 return GestureDetector(
281 behavior: HitTestBehavior.opaque, 282 behavior: HitTestBehavior.opaque,
282 - onTap: () => showTodayFaqBottomSheet(), 283 + onTap: () => text == l10n.todayFaqLinkHrvRealtimeUpdate
  284 + ? showRealtimeStressExplanationBottomSheet(Get.context!)
  285 + : showTodayFaqBottomSheet(text: text),
283 child: Padding( 286 child: Padding(
284 padding: const EdgeInsets.only(bottom: 14), 287 padding: const EdgeInsets.only(bottom: 14),
285 child: Text( 288 child: Text(
  1 +import 'package:doublefeel_flutter/app/modules/home/widgets/today/hrv_principle_explanation_bottom_sheet.dart';
1 import 'package:doublefeel_flutter/core/theme/app_theme.dart'; 2 import 'package:doublefeel_flutter/core/theme/app_theme.dart';
2 import 'package:doublefeel_flutter/l10n/l10n_extensions.dart'; 3 import 'package:doublefeel_flutter/l10n/l10n_extensions.dart';
3 import 'package:flutter/material.dart'; 4 import 'package:flutter/material.dart';
@@ -293,7 +294,6 @@ class _FaqLinksCard extends StatelessWidget { @@ -293,7 +294,6 @@ class _FaqLinksCard extends StatelessWidget {
293 title: l10n.todayFaqSectionTitle, 294 title: l10n.todayFaqSectionTitle,
294 children: [ 295 children: [
295 _FaqLink(l10n.todayFaqLinkNoData), 296 _FaqLink(l10n.todayFaqLinkNoData),
296 - _FaqLink(l10n.todayFaqLinkHrvRealtimeUpdate),  
297 _FaqLink(l10n.todayFaqLinkWatchNoStatusNotification), 297 _FaqLink(l10n.todayFaqLinkWatchNoStatusNotification),
298 _FaqLink(l10n.todayFaqLinkWatchFaceDataDelay), 298 _FaqLink(l10n.todayFaqLinkWatchFaceDataDelay),
299 _FaqLink(l10n.todayFaqLinkWatchFaceBlackScreen), 299 _FaqLink(l10n.todayFaqLinkWatchFaceBlackScreen),
@@ -311,7 +311,9 @@ class _FaqLink extends StatelessWidget { @@ -311,7 +311,9 @@ class _FaqLink extends StatelessWidget {
311 Widget build(BuildContext context) { 311 Widget build(BuildContext context) {
312 return GestureDetector( 312 return GestureDetector(
313 behavior: HitTestBehavior.opaque, 313 behavior: HitTestBehavior.opaque,
314 - onTap: () => showTodayFaqBottomSheet(), 314 + onTap: () => text == l10n.todayFaqLinkHrvRealtimeUpdate
  315 + ? showRealtimeStressExplanationBottomSheet(Get.context!)
  316 + : showTodayFaqBottomSheet(text: text),
315 child: Padding( 317 child: Padding(
316 padding: const EdgeInsets.only(bottom: 14), 318 padding: const EdgeInsets.only(bottom: 14),
317 child: Text( 319 child: Text(
  1 +import 'package:doublefeel_flutter/app/modules/home/widgets/today/hrv_principle_explanation_bottom_sheet.dart';
  2 +import 'package:doublefeel_flutter/app/modules/home/widgets/today/realtime_stress_explanation_bottom_sheet.dart';
1 import 'package:doublefeel_flutter/core/theme/app_theme.dart'; 3 import 'package:doublefeel_flutter/core/theme/app_theme.dart';
2 import 'package:doublefeel_flutter/l10n/l10n_extensions.dart'; 4 import 'package:doublefeel_flutter/l10n/l10n_extensions.dart';
3 import 'package:flutter/material.dart'; 5 import 'package:flutter/material.dart';
@@ -312,7 +314,9 @@ class _FaqLink extends StatelessWidget { @@ -312,7 +314,9 @@ class _FaqLink extends StatelessWidget {
312 Widget build(BuildContext context) { 314 Widget build(BuildContext context) {
313 return GestureDetector( 315 return GestureDetector(
314 behavior: HitTestBehavior.opaque, 316 behavior: HitTestBehavior.opaque,
315 - onTap: () => showTodayFaqBottomSheet(), 317 + onTap: () => text == l10n.todayFaqLinkHrvRealtimeUpdate
  318 + ? showRealtimeStressExplanationBottomSheet(Get.context!)
  319 + : showTodayFaqBottomSheet(text: text),
316 child: Padding( 320 child: Padding(
317 padding: const EdgeInsets.only(bottom: 14), 321 padding: const EdgeInsets.only(bottom: 14),
318 child: Text( 322 child: Text(
@@ -5,7 +5,7 @@ import 'package:flutter/gestures.dart'; @@ -5,7 +5,7 @@ import 'package:flutter/gestures.dart';
5 import 'package:flutter/material.dart'; 5 import 'package:flutter/material.dart';
6 import 'package:get/get.dart'; 6 import 'package:get/get.dart';
7 7
8 -void showTodayFaqBottomSheet() { 8 +void showTodayFaqBottomSheet({String? text}) {
9 final view = WidgetsBinding.instance.platformDispatcher.views.first; 9 final view = WidgetsBinding.instance.platformDispatcher.views.first;
10 final devicePixelRatio = view.devicePixelRatio; 10 final devicePixelRatio = view.devicePixelRatio;
11 final screenHeight = view.physicalSize.height / devicePixelRatio; 11 final screenHeight = view.physicalSize.height / devicePixelRatio;
@@ -20,6 +20,7 @@ void showTodayFaqBottomSheet() { @@ -20,6 +20,7 @@ void showTodayFaqBottomSheet() {
20 builder: (context, scrollController) { 20 builder: (context, scrollController) {
21 return TodayFaqBottomSheet( 21 return TodayFaqBottomSheet(
22 scrollController: scrollController, 22 scrollController: scrollController,
  23 + scrollToText: text,
23 ); 24 );
24 }, 25 },
25 ), 26 ),
@@ -30,13 +31,78 @@ void showTodayFaqBottomSheet() { @@ -30,13 +31,78 @@ void showTodayFaqBottomSheet() {
30 ); 31 );
31 } 32 }
32 33
33 -class TodayFaqBottomSheet extends StatelessWidget { 34 +class TodayFaqBottomSheet extends StatefulWidget {
34 const TodayFaqBottomSheet({ 35 const TodayFaqBottomSheet({
35 super.key, 36 super.key,
36 required this.scrollController, 37 required this.scrollController,
  38 + this.scrollToText,
37 }); 39 });
38 40
39 final ScrollController scrollController; 41 final ScrollController scrollController;
  42 + final String? scrollToText;
  43 +
  44 + @override
  45 + State<TodayFaqBottomSheet> createState() => _TodayFaqBottomSheetState();
  46 +}
  47 +
  48 +class _TodayFaqBottomSheetState extends State<TodayFaqBottomSheet> {
  49 + // 为每个 FAQ 卡片分配 GlobalKey,用于定位渲染位置
  50 + final _noDataKey = GlobalKey();
  51 + final _watchNoNotificationKey = GlobalKey();
  52 + final _watchFaceDelayKey = GlobalKey();
  53 + final _watchFaceBlackScreenKey = GlobalKey();
  54 +
  55 + @override
  56 + void initState() {
  57 + super.initState();
  58 + if (widget.scrollToText != null) {
  59 + // 等第一帧渲染完成后,计算目标卡片位置并滚动
  60 + WidgetsBinding.instance.addPostFrameCallback((_) => _scrollToTarget());
  61 + }
  62 + }
  63 +
  64 + void _scrollToTarget() {
  65 + final l10n = context.l10n;
  66 + final text = widget.scrollToText;
  67 +
  68 + GlobalKey? targetKey;
  69 + if (text == l10n.todayFaqLinkNoData) {
  70 + targetKey = _noDataKey;
  71 + } else if (text == l10n.todayFaqLinkWatchNoStatusNotification ||
  72 + text == l10n.todayFaqLinkWatchNoStatusAndInteractionNotification) {
  73 + targetKey = _watchNoNotificationKey;
  74 + } else if (text == l10n.todayFaqLinkWatchFaceDataDelay) {
  75 + targetKey = _watchFaceDelayKey;
  76 + } else if (text == l10n.todayFaqLinkWatchFaceBlackScreen) {
  77 + targetKey = _watchFaceBlackScreenKey;
  78 + }
  79 +
  80 + if (targetKey == null) return;
  81 +
  82 + final renderBox =
  83 + targetKey.currentContext?.findRenderObject() as RenderBox?;
  84 + if (renderBox == null) return;
  85 +
  86 + // 将目标卡片的本地坐标转换为 ListView 滚动视图坐标系中的偏移量
  87 + final listRenderObject = widget
  88 + .scrollController.position.context.storageContext
  89 + .findRenderObject();
  90 + if (listRenderObject == null) return;
  91 +
  92 + final targetOffset =
  93 + renderBox.localToGlobal(Offset.zero, ancestor: listRenderObject);
  94 + final currentOffset = widget.scrollController.offset;
  95 + final targetScrollOffset = (currentOffset + targetOffset.dy).clamp(
  96 + widget.scrollController.position.minScrollExtent,
  97 + widget.scrollController.position.maxScrollExtent,
  98 + );
  99 +
  100 + widget.scrollController.animateTo(
  101 + targetScrollOffset,
  102 + duration: const Duration(milliseconds: 350),
  103 + curve: Curves.easeInOut,
  104 + );
  105 + }
40 106
41 @override 107 @override
42 Widget build(BuildContext context) { 108 Widget build(BuildContext context) {
@@ -90,11 +156,12 @@ class TodayFaqBottomSheet extends StatelessWidget { @@ -90,11 +156,12 @@ class TodayFaqBottomSheet extends StatelessWidget {
90 ), 156 ),
91 Expanded( 157 Expanded(
92 child: ListView( 158 child: ListView(
93 - controller: scrollController, 159 + controller: widget.scrollController,
94 physics: const ClampingScrollPhysics(), 160 physics: const ClampingScrollPhysics(),
95 padding: const EdgeInsets.fromLTRB(16, 8, 16, 20), 161 padding: const EdgeInsets.fromLTRB(16, 8, 16, 20),
96 children: [ 162 children: [
97 _InfoCard( 163 _InfoCard(
  164 + key: _noDataKey,
98 title: l10n.todayFaqNoDataTitle, 165 title: l10n.todayFaqNoDataTitle,
99 children: [ 166 children: [
100 _InfoText( 167 _InfoText(
@@ -110,6 +177,7 @@ class TodayFaqBottomSheet extends StatelessWidget { @@ -110,6 +177,7 @@ class TodayFaqBottomSheet extends StatelessWidget {
110 ), 177 ),
111 const SizedBox(height: 12), 178 const SizedBox(height: 12),
112 _InfoCard( 179 _InfoCard(
  180 + key: _watchNoNotificationKey,
113 title: l10n.todayFaqWatchNoNotificationTitle, 181 title: l10n.todayFaqWatchNoNotificationTitle,
114 children: [ 182 children: [
115 _InfoText( 183 _InfoText(
@@ -135,6 +203,7 @@ class TodayFaqBottomSheet extends StatelessWidget { @@ -135,6 +203,7 @@ class TodayFaqBottomSheet extends StatelessWidget {
135 ), 203 ),
136 const SizedBox(height: 12), 204 const SizedBox(height: 12),
137 _InfoCard( 205 _InfoCard(
  206 + key: _watchFaceDelayKey,
138 title: l10n.todayFaqWatchFaceDelayTitle, 207 title: l10n.todayFaqWatchFaceDelayTitle,
139 children: [ 208 children: [
140 _InfoText( 209 _InfoText(
@@ -156,6 +225,7 @@ class TodayFaqBottomSheet extends StatelessWidget { @@ -156,6 +225,7 @@ class TodayFaqBottomSheet extends StatelessWidget {
156 ), 225 ),
157 const SizedBox(height: 12), 226 const SizedBox(height: 12),
158 _InfoCard( 227 _InfoCard(
  228 + key: _watchFaceBlackScreenKey,
159 title: l10n.todayFaqWatchFaceBlackScreenTitle, 229 title: l10n.todayFaqWatchFaceBlackScreenTitle,
160 children: [ 230 children: [
161 _InfoText( 231 _InfoText(
@@ -175,6 +245,7 @@ class TodayFaqBottomSheet extends StatelessWidget { @@ -175,6 +245,7 @@ class TodayFaqBottomSheet extends StatelessWidget {
175 245
176 class _InfoCard extends StatelessWidget { 246 class _InfoCard extends StatelessWidget {
177 const _InfoCard({ 247 const _InfoCard({
  248 + super.key,
178 required this.title, 249 required this.title,
179 required this.children, 250 required this.children,
180 }); 251 });