|
...
|
...
|
@@ -5,7 +5,7 @@ import 'package:flutter/gestures.dart'; |
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
import 'package:get/get.dart';
|
|
|
|
|
|
|
|
void showTodayFaqBottomSheet() {
|
|
|
|
void showTodayFaqBottomSheet({String? text}) {
|
|
|
|
final view = WidgetsBinding.instance.platformDispatcher.views.first;
|
|
|
|
final devicePixelRatio = view.devicePixelRatio;
|
|
|
|
final screenHeight = view.physicalSize.height / devicePixelRatio;
|
|
...
|
...
|
@@ -20,6 +20,7 @@ void showTodayFaqBottomSheet() { |
|
|
|
builder: (context, scrollController) {
|
|
|
|
return TodayFaqBottomSheet(
|
|
|
|
scrollController: scrollController,
|
|
|
|
scrollToText: text,
|
|
|
|
);
|
|
|
|
},
|
|
|
|
),
|
|
...
|
...
|
@@ -30,13 +31,78 @@ void showTodayFaqBottomSheet() { |
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
class TodayFaqBottomSheet extends StatelessWidget {
|
|
|
|
class TodayFaqBottomSheet extends StatefulWidget {
|
|
|
|
const TodayFaqBottomSheet({
|
|
|
|
super.key,
|
|
|
|
required this.scrollController,
|
|
|
|
this.scrollToText,
|
|
|
|
});
|
|
|
|
|
|
|
|
final ScrollController scrollController;
|
|
|
|
final String? scrollToText;
|
|
|
|
|
|
|
|
@override
|
|
|
|
State<TodayFaqBottomSheet> createState() => _TodayFaqBottomSheetState();
|
|
|
|
}
|
|
|
|
|
|
|
|
class _TodayFaqBottomSheetState extends State<TodayFaqBottomSheet> {
|
|
|
|
// 为每个 FAQ 卡片分配 GlobalKey,用于定位渲染位置
|
|
|
|
final _noDataKey = GlobalKey();
|
|
|
|
final _watchNoNotificationKey = GlobalKey();
|
|
|
|
final _watchFaceDelayKey = GlobalKey();
|
|
|
|
final _watchFaceBlackScreenKey = GlobalKey();
|
|
|
|
|
|
|
|
@override
|
|
|
|
void initState() {
|
|
|
|
super.initState();
|
|
|
|
if (widget.scrollToText != null) {
|
|
|
|
// 等第一帧渲染完成后,计算目标卡片位置并滚动
|
|
|
|
WidgetsBinding.instance.addPostFrameCallback((_) => _scrollToTarget());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void _scrollToTarget() {
|
|
|
|
final l10n = context.l10n;
|
|
|
|
final text = widget.scrollToText;
|
|
|
|
|
|
|
|
GlobalKey? targetKey;
|
|
|
|
if (text == l10n.todayFaqLinkNoData) {
|
|
|
|
targetKey = _noDataKey;
|
|
|
|
} else if (text == l10n.todayFaqLinkWatchNoStatusNotification ||
|
|
|
|
text == l10n.todayFaqLinkWatchNoStatusAndInteractionNotification) {
|
|
|
|
targetKey = _watchNoNotificationKey;
|
|
|
|
} else if (text == l10n.todayFaqLinkWatchFaceDataDelay) {
|
|
|
|
targetKey = _watchFaceDelayKey;
|
|
|
|
} else if (text == l10n.todayFaqLinkWatchFaceBlackScreen) {
|
|
|
|
targetKey = _watchFaceBlackScreenKey;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (targetKey == null) return;
|
|
|
|
|
|
|
|
final renderBox =
|
|
|
|
targetKey.currentContext?.findRenderObject() as RenderBox?;
|
|
|
|
if (renderBox == null) return;
|
|
|
|
|
|
|
|
// 将目标卡片的本地坐标转换为 ListView 滚动视图坐标系中的偏移量
|
|
|
|
final listRenderObject = widget
|
|
|
|
.scrollController.position.context.storageContext
|
|
|
|
.findRenderObject();
|
|
|
|
if (listRenderObject == null) return;
|
|
|
|
|
|
|
|
final targetOffset =
|
|
|
|
renderBox.localToGlobal(Offset.zero, ancestor: listRenderObject);
|
|
|
|
final currentOffset = widget.scrollController.offset;
|
|
|
|
final targetScrollOffset = (currentOffset + targetOffset.dy).clamp(
|
|
|
|
widget.scrollController.position.minScrollExtent,
|
|
|
|
widget.scrollController.position.maxScrollExtent,
|
|
|
|
);
|
|
|
|
|
|
|
|
widget.scrollController.animateTo(
|
|
|
|
targetScrollOffset,
|
|
|
|
duration: const Duration(milliseconds: 350),
|
|
|
|
curve: Curves.easeInOut,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
Widget build(BuildContext context) {
|
|
...
|
...
|
@@ -90,11 +156,12 @@ class TodayFaqBottomSheet extends StatelessWidget { |
|
|
|
),
|
|
|
|
Expanded(
|
|
|
|
child: ListView(
|
|
|
|
controller: scrollController,
|
|
|
|
controller: widget.scrollController,
|
|
|
|
physics: const ClampingScrollPhysics(),
|
|
|
|
padding: const EdgeInsets.fromLTRB(16, 8, 16, 20),
|
|
|
|
children: [
|
|
|
|
_InfoCard(
|
|
|
|
key: _noDataKey,
|
|
|
|
title: l10n.todayFaqNoDataTitle,
|
|
|
|
children: [
|
|
|
|
_InfoText(
|
|
...
|
...
|
@@ -110,6 +177,7 @@ class TodayFaqBottomSheet extends StatelessWidget { |
|
|
|
),
|
|
|
|
const SizedBox(height: 12),
|
|
|
|
_InfoCard(
|
|
|
|
key: _watchNoNotificationKey,
|
|
|
|
title: l10n.todayFaqWatchNoNotificationTitle,
|
|
|
|
children: [
|
|
|
|
_InfoText(
|
|
...
|
...
|
@@ -135,6 +203,7 @@ class TodayFaqBottomSheet extends StatelessWidget { |
|
|
|
),
|
|
|
|
const SizedBox(height: 12),
|
|
|
|
_InfoCard(
|
|
|
|
key: _watchFaceDelayKey,
|
|
|
|
title: l10n.todayFaqWatchFaceDelayTitle,
|
|
|
|
children: [
|
|
|
|
_InfoText(
|
|
...
|
...
|
@@ -156,6 +225,7 @@ class TodayFaqBottomSheet extends StatelessWidget { |
|
|
|
),
|
|
|
|
const SizedBox(height: 12),
|
|
|
|
_InfoCard(
|
|
|
|
key: _watchFaceBlackScreenKey,
|
|
|
|
title: l10n.todayFaqWatchFaceBlackScreenTitle,
|
|
|
|
children: [
|
|
|
|
_InfoText(
|
|
...
|
...
|
@@ -175,6 +245,7 @@ class TodayFaqBottomSheet extends StatelessWidget { |
|
|
|
|
|
|
|
class _InfoCard extends StatelessWidget {
|
|
|
|
const _InfoCard({
|
|
|
|
super.key,
|
|
|
|
required this.title,
|
|
|
|
required this.children,
|
|
|
|
});
|
...
|
...
|
|