Commit 9b3061e1d15ddf34d0646984127cca9aec720b68

Authored by 常守达
1 parent 1c42efc7

feat(today): 首页UI

import 'dart:async';
import 'package:doublefeel_flutter/app/modules/home/views/no_health_data_page.dart';
import 'package:doublefeel_flutter/core/logging/app_logger.dart';
import 'package:doublefeel_flutter/core/network/api/health_api.dart';
import 'package:doublefeel_flutter/core/network/api/user_api.dart';
... ... @@ -101,12 +102,13 @@ class TodayController extends GetxController {
final hrvAnnotations = <HrvAnnotation>[].obs;
Future<void> requestHealthAuthorization() async {
try {
await _healthKitUploadService.requestClientAuthorization();
await _refreshHealthAuthorizationState();
} catch (error) {
debugPrint('Health authorization skipped: $error');
}
// try {
// await _healthKitUploadService.requestClientAuthorization();
// await _refreshHealthAuthorizationState();
// } catch (error) {
// debugPrint('Health authorization skipped: $error');
// }
Get.to(NoHealthDataPage());
}
@override
... ... @@ -199,7 +201,8 @@ class TodayController extends GetxController {
isOther: false,
errorHandlingPolicy: null,
)
: Future.value(AppFailure<TodayStatusData>(AppUnknownError('Not today')));
: Future.value(
AppFailure<TodayStatusData>(AppUnknownError('Not today')));
final latestHrvResultFuture = isToday
? _healthApi.getLatestHrvData(
... ... @@ -395,7 +398,8 @@ class TodayController extends GetxController {
}
}
void _applyActivityStatistics(ActivityBurnStatisticsData data, DateTime date) {
void _applyActivityStatistics(
ActivityBurnStatisticsData data, DateTime date) {
_activityMoveTarget = data.activityTargetInfo?.move ?? _activityMoveTarget;
_activityStandTarget =
data.activityTargetInfo?.stand ?? _activityStandTarget;
... ...
import 'package:doublefeel_flutter/core/theme/app_theme.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
class NoHealthDataPage extends StatelessWidget {
const NoHealthDataPage({
super.key,
this.onRefresh,
this.onHelp,
});
static const _backgroundColor = Color(0xFFF5F2FF);
static const _placeholderColor = Color(0xFFD9D9D9);
static const _imagePlaceholderColor = Color(0xFFF3F3F3);
static const _screenShotBackground = Color(0xFFF2F2F6);
final VoidCallback? onRefresh;
final VoidCallback? onHelp;
@override
Widget build(BuildContext context) {
return AnnotatedRegion<SystemUiOverlayStyle>(
value: AppTheme.systemUiOverlayStyle.copyWith(
systemNavigationBarColor: _backgroundColor,
),
child: Scaffold(
backgroundColor: _backgroundColor,
body: Column(
children: [
SafeArea(
bottom: false,
child: _TopBar(onRefresh: onRefresh),
),
Expanded(
child: ListView(
physics: const ClampingScrollPhysics(),
padding: EdgeInsets.fromLTRB(
16,
4,
16,
20 + MediaQuery.paddingOf(context).bottom,
),
children: [
const _PageHeading(),
const SizedBox(height: 24),
const _InfoCard(
title: '错误1:Apple Watch 数据不可用',
body:
'看起来你在过去 12 个月内没有使用 Apple Watch。如果你刚开始使用 Apple Watch 并已启用所有数据权限,这条信息可能仍会出现。请继续佩戴 Apple Watch 以允许数据采集,或在首页手动添加 HRV 数据。',
),
const SizedBox(height: 12),
const _AuthorizationCard(),
const SizedBox(height: 12),
const _SystemIssueCard(),
const SizedBox(height: 16),
Center(
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: onHelp,
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 4,
),
child: Text(
'需要帮助?',
style: TextStyle(
color: context.colors.primary,
fontSize: 12,
fontWeight: FontWeight.w400,
height: 17 / 12,
),
),
),
),
),
],
),
),
],
),
),
);
}
}
class _TopBar extends StatelessWidget {
const _TopBar({this.onRefresh});
final VoidCallback? onRefresh;
@override
Widget build(BuildContext context) {
return SizedBox(
height: 44,
child: Stack(
children: [
Positioned(
left: 4,
top: 0,
bottom: 0,
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () => Get.back<void>(),
child: const SizedBox(
width: 44,
height: 44,
child: Center(
child: Image(
image: AssetImage('assets/images/common/ic_nav_back.webp'),
width: 24,
height: 24,
),
),
),
),
),
Positioned(
right: 16,
top: 0,
bottom: 0,
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: onRefresh,
child: Center(
child: Text(
'刷新',
style: TextStyle(
color: context.colors.primary,
fontSize: 14,
fontWeight: FontWeight.w400,
height: 20 / 14,
),
),
),
),
),
],
),
);
}
}
class _PageHeading extends StatelessWidget {
const _PageHeading();
@override
Widget build(BuildContext context) {
return Column(
children: [
Padding(
padding: EdgeInsets.symmetric(horizontal: 21),
child: Text(
'无心率数据可用',
textAlign: TextAlign.center,
style: TextStyle(
color: Color(0xFF14121E),
fontSize: 20,
fontWeight: FontWeight.w600,
height: 28 / 20,
),
),
),
SizedBox(height: 8),
Padding(
padding: EdgeInsets.symmetric(horizontal: 8),
child: Text(
'DoubleFeel无法从 Apple Health 获取你的 HRV 数据。请按照提示授予权限,然后点击右上角“刷新”继续。',
textAlign: TextAlign.center,
style: TextStyle(
color: context.colors.textPrimary,
fontSize: 14,
fontWeight: FontWeight.w400,
height: 18 / 14,
),
),
),
],
);
}
}
class _InfoCard extends StatelessWidget {
const _InfoCard({
required this.title,
required this.body,
});
final String title;
final String body;
@override
Widget build(BuildContext context) {
return _CardShell(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Center(child: _IconPlaceholder()),
const SizedBox(height: 10),
Text(
title,
style: TextStyle(
color: Colors.black,
fontSize: 16,
fontWeight: FontWeight.w600,
height: 22 / 16,
),
),
const SizedBox(height: 6),
Text(
body,
style: TextStyle(
color: context.colors.textSecondary,
fontSize: 12,
fontWeight: FontWeight.w400,
height: 17 / 12,
),
),
],
),
);
}
}
class _AuthorizationCard extends StatelessWidget {
const _AuthorizationCard();
@override
Widget build(BuildContext context) {
return _CardShell(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Center(child: _IconPlaceholder()),
SizedBox(height: 10),
Text(
'错误 2:健康数据访问未授权',
style: TextStyle(
color: Colors.black,
fontSize: 16,
fontWeight: FontWeight.w600,
height: 22 / 16,
),
),
SizedBox(height: 6),
Text(
'DoubleFeel 需要访问 Apple Health 数据的权限,以提供压力统计、提醒和建议。如果未授权,部分功能可能无法正常使用。\n\n请放心,所有健康数据仅存储在本地,不会上传。\n\n要启用权限,请按提示操作,并在 iOS 设置中选择 允许所有 → 健康 → DoubleFeel。',
style: TextStyle(
color: context.colors.textSecondary,
fontSize: 12,
fontWeight: FontWeight.w400,
height: 17 / 12,
),
),
SizedBox(height: 37),
Image.asset(
'assets/images/today/health_data_permission_step_1.png',
height: 140,
alignment: Alignment(0, 0.12),
),
SizedBox(height: 20),
Image.asset(
'assets/images/today/health_data_permission_step_2.png',
height: 172,
alignment: Alignment(0, 0.24),
),
SizedBox(height: 20),
Image.asset(
'assets/images/today/health_data_permission_step_3.png',
height: 210,
alignment: Alignment(0, -0.13),
),
SizedBox(height: 20),
Image.asset(
'assets/images/today/health_data_permission_step_4.png',
height: 167,
alignment: Alignment(0, -0.54),
),
],
),
);
}
}
class _SystemIssueCard extends StatelessWidget {
const _SystemIssueCard();
@override
Widget build(BuildContext context) {
return _CardShell(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Center(child: _IconPlaceholder()),
SizedBox(height: 10),
Text(
'错误 3:系统问题',
style: TextStyle(
color: Colors.black,
fontSize: 16,
fontWeight: FontWeight.w600,
height: 22 / 16,
),
),
SizedBox(height: 6),
Text(
'根据用户反馈,我们发现 HRV 或心率数据可能缺失的两个原因:\n\n'
'1. Apple Watch 未连接\n'
' · 如果你的 Apple Watch 长时间未佩戴,心率数据可能无法采集。\n'
' · 请检查 iOS 健康 App → “我的手表”,确认最近的心率数据是否在佩戴 Apple Watch 时记录。\n'
' · 如果没有,请尝试佩戴 Apple Watch 进行数据采集,并打开 Apple 支持的心率功能。\n\n'
'2. 过去 30 天的心率或 HRV 数据缺失\n'
' · 打开 iOS 健康 App → 浏览 → “心率” 或 “HRV” → “未找到数据”,确认是否缺失。\n'
' · 如果数据缺失,请重新佩戴手表,并重启 iPhone 和 Apple Watch 后,再次打开 DoubleFeel。',
style: TextStyle(
color: context.colors.textSecondary,
fontSize: 12,
fontWeight: FontWeight.w400,
height: 17 / 12,
),
),
],
),
);
}
}
class _CardShell extends StatelessWidget {
const _CardShell({required this.child});
final Widget child;
@override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
padding: const EdgeInsets.fromLTRB(20, 20, 20, 20),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
),
child: child,
);
}
}
class _IconPlaceholder extends StatelessWidget {
const _IconPlaceholder();
@override
Widget build(BuildContext context) {
return Container(
width: 56,
height: 56,
color: NoHealthDataPage._placeholderColor,
);
}
}
... ...
import 'package:doublefeel_flutter/core/services/user_state_service.dart';
import 'package:doublefeel_flutter/core/theme/app_theme.dart';
import 'package:doublefeel_flutter/l10n/l10n_extensions.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:table_calendar/table_calendar.dart';
import '../../controllers/today_controller.dart';
import '../../widgets/today/hrv_measurement_bottom_sheet.dart';
import '../../widgets/today/today_health_data_auth_card.dart';
import '../../widgets/today/today_hrv_ad_banner.dart';
import '../../widgets/today/today_hrv_number_card.dart';
import '../../widgets/today/today_hrv_chart_card.dart';
import '../../widgets/today/today_hrv_number_card.dart';
import '../../widgets/today/today_sleep_activity_cards.dart';
import '../../widgets/today/stress_status_explanation_bottom_sheet.dart';
import '../../widgets/today/premium_card.dart';
... ... @@ -110,13 +113,29 @@ class TodayTab extends GetView<TodayController> {
mainAxisAlignment: MainAxisAlignment.end,
children: [
Obx(
() => Text(
controller.stressSubtitle.value,
textAlign: TextAlign.center,
style: const TextStyle(
color: Color(0xFF78787D),
fontSize: 14,
fontWeight: FontWeight.w500,
() => GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: showStressStatusExplanationBottomSheet,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
controller.stressSubtitle.value,
textAlign: TextAlign.center,
style: const TextStyle(
color: Color(0xFF78787D),
fontSize: 14,
fontWeight: FontWeight.w500,
),
),
const SizedBox(width: 4),
Image.asset(
'assets/images/common/ic_info.png',
width: 14,
height: 14,
color: const Color(0xFF78787D),
),
],
),
),
),
... ... @@ -124,8 +143,8 @@ class TodayTab extends GetView<TodayController> {
() => Text(
controller.stressLabel.value,
textAlign: TextAlign.center,
style: const TextStyle(
color: Color(0xFF0F0F11),
style: TextStyle(
color: context.colors.textPrimary,
fontSize: 28,
fontWeight: FontWeight.w500,
),
... ... @@ -161,21 +180,7 @@ class TodayTab extends GetView<TodayController> {
const TodaySleepCard(),
const TodayActivityCard(),
const SizedBox(height: 4),
Container(
padding: const EdgeInsets.fromLTRB(20, 20, 20, 16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
),
child: const Text(
'立即测量HRV',
style: TextStyle(
color: Color(0xFF0F0F11),
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
),
measureHRVButton(context),
Container(
alignment: Alignment.center,
margin: EdgeInsets.only(
... ... @@ -195,6 +200,27 @@ class TodayTab extends GetView<TodayController> {
);
}
Widget measureHRVButton(BuildContext context) {
return GestureDetector(
onTap: showHrvMeasurementBottomSheet,
child: Container(
padding: const EdgeInsets.fromLTRB(20, 20, 20, 16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
),
child: Text(
context.l10n.measureYourHrvNow,
style: TextStyle(
color: context.colors.textPrimary,
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
),
);
}
Widget _buildWeekCalendar(BuildContext context) {
return SizedBox(
height: _weekCalendarHeight,
... ... @@ -224,7 +250,6 @@ class TodayTab extends GetView<TodayController> {
selectedDayPredicate: (day) =>
isSameDay(controller.selectedDate.value, day),
onDaySelected: _onDaySelected,
onPageChanged: _onCalendarPageChanged,
calendarStyle: const CalendarStyle(
cellMargin: EdgeInsets.zero,
cellPadding: EdgeInsets.zero,
... ... @@ -235,7 +260,8 @@ class TodayTab extends GetView<TodayController> {
decoration: BoxDecoration(),
),
calendarBuilders: CalendarBuilders(
dowBuilder: (context, day) => _buildWeekdayCell(context, day),
dowBuilder: (context, day) =>
_buildWeekdayCell(context, day),
defaultBuilder: (context, day, focusedDay) =>
_buildDateCell(context, day),
disabledBuilder: (context, day, focusedDay) =>
... ... @@ -288,7 +314,9 @@ class TodayTab extends GetView<TodayController> {
)
: null,
child: Text(
isSameDay(day, controller.lastSelectableDay) ? '今' : _weekdayText(day),
isSameDay(day, controller.lastSelectableDay)
? '今'
: _weekdayText(day),
style: TextStyle(
color: _calendarTextColor(context, day, selected: selected),
fontSize: 12,
... ... @@ -333,23 +361,10 @@ class TodayTab extends GetView<TodayController> {
controller.changeDate(selectedDay, focused: focusedDay);
}
void _onCalendarPageChanged(DateTime focusedDay) {
final selectedWeekdayOffset =
controller.selectedDate.value.weekday - DateTime.monday;
final nextSelectedDay =
_weekStart(focusedDay).add(Duration(days: selectedWeekdayOffset));
controller.changeDate(nextSelectedDay, focused: focusedDay);
}
void _backToToday() {
controller.changeDate(controller.lastSelectableDay);
}
DateTime _weekStart(DateTime day) {
final normalizedDay = DateUtils.dateOnly(day);
return normalizedDay.subtract(Duration(days: normalizedDay.weekday - 1));
}
String _dateTitle(DateTime selectedDay) {
final today = controller.lastSelectableDay;
if (isSameDay(selectedDay, today)) return '今日';
... ...
import 'package:doublefeel_flutter/core/theme/app_theme.dart';
import 'package:doublefeel_flutter/l10n/l10n_extensions.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
void showHrvMeasurementBottomSheet() {
Get.bottomSheet(
const FractionallySizedBox(
heightFactor: 0.9,
child: HrvMeasurementBottomSheet(),
),
barrierColor: Colors.black.withValues(alpha: 0.7),
enableDrag: true,
isScrollControlled: true,
persistent: false,
);
}
class HrvMeasurementBottomSheet extends StatelessWidget {
const HrvMeasurementBottomSheet({super.key});
@override
Widget build(BuildContext context) {
final l10n = context.l10n;
return Container(
decoration: const BoxDecoration(
color: Color(0xFFF5F2FF),
borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
),
child: SafeArea(
top: false,
child: Column(
children: [
SizedBox(
height: 64,
child: Stack(
alignment: Alignment.center,
children: [
Positioned(
left: 16,
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: Get.back,
child: SizedBox(
width: 44,
height: 44,
child: Center(
child: Image.asset(
'assets/images/common/ic_close.png',
width: 20,
height: 20,
color: context.colors.chartPurple,
),
),
),
),
),
],
),
),
Expanded(
child: Padding(
padding: const EdgeInsets.fromLTRB(16, 8, 16, 16),
child: Center(
child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 342),
child: const _HrvInstructionCard(),
),
),
),
),
Container(
height: 48,
width: 280,
margin: const EdgeInsets.only(bottom: 20),
child: ElevatedButton(
onPressed: Get.back,
style: ElevatedButton.styleFrom(
backgroundColor: context.colors.primary,
foregroundColor: Colors.white,
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(24),
),
),
child: Text(
l10n.todayBottomSheetGotIt,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
),
),
],
),
),
);
}
}
class _HrvInstructionCard extends StatelessWidget {
const _HrvInstructionCard();
@override
Widget build(BuildContext context) {
final l10n = context.l10n;
return Stack(
alignment: Alignment.topCenter,
children: [
Container(
constraints: const BoxConstraints(minHeight: 438),
margin: const EdgeInsets.only(top: 110),
padding: const EdgeInsets.fromLTRB(20, 78, 20, 20),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
l10n.todayHrvMeasurementIntro,
style: TextStyle(
color: context.colors.textSecondary,
fontSize: 12,
height: 17 / 12,
fontWeight: FontWeight.w400,
),
),
const SizedBox(height: 18),
_InstructionStep(text: l10n.todayHrvMeasurementStep1),
const SizedBox(height: 8),
_InstructionStep(text: l10n.todayHrvMeasurementStep2),
const SizedBox(height: 8),
_InstructionStep(text: l10n.todayHrvMeasurementStep3),
const SizedBox(height: 8),
_InstructionStep(text: l10n.todayHrvMeasurementStep4),
const SizedBox(height: 8),
_InstructionStep(text: l10n.todayHrvMeasurementStep5),
const SizedBox(height: 16),
Text(
l10n.todayHrvMeasurementHint,
style: TextStyle(
color: context.colors.textSecondary,
fontSize: 12,
height: 17 / 12,
fontWeight: FontWeight.w400,
),
),
const SizedBox(height: 8),
Text(
l10n.todayHrvMeasurementWarning,
style: TextStyle(
color: context.colors.warning,
fontSize: 12,
height: 17 / 12,
fontWeight: FontWeight.w400,
),
),
],
),
),
Image.asset(
'assets/images/today/hrv_measure_watch.png',
width: 110,
height: 172,
fit: BoxFit.contain,
),
],
);
}
}
class _InstructionStep extends StatelessWidget {
const _InstructionStep({required this.text});
final String text;
@override
Widget build(BuildContext context) {
return Text(
text,
style: TextStyle(
color: context.colors.textPrimary,
fontSize: 14,
height: 20 / 14,
fontWeight: FontWeight.w400,
),
);
}
}
... ...
import 'package:doublefeel_flutter/core/theme/app_theme.dart';
import 'package:doublefeel_flutter/l10n/l10n_extensions.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'today_faq_bottom_sheet.dart';
void showHrvPrincipleExplanationBottomSheet() {
Get.bottomSheet(
DraggableScrollableSheet(
initialChildSize: 0.96,
minChildSize: 0.2,
maxChildSize: 0.96,
expand: false,
snap: true,
builder: (context, scrollController) {
return HrvPrincipleExplanationBottomSheet(
scrollController: scrollController,
);
},
),
barrierColor: Colors.black.withValues(alpha: 0.7),
enableDrag: true,
isScrollControlled: true,
persistent: false,
);
}
class HrvPrincipleExplanationBottomSheet extends StatelessWidget {
const HrvPrincipleExplanationBottomSheet({
super.key,
required this.scrollController,
});
final ScrollController scrollController;
@override
Widget build(BuildContext context) {
final l10n = context.l10n;
return Container(
decoration: const BoxDecoration(
color: Color(0xFFF5F2FF),
borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
),
child: SafeArea(
top: false,
child: Column(
children: [
SizedBox(
height: 64,
child: Stack(
alignment: Alignment.center,
children: [
Center(
child: Text(
l10n.todayHrvPrincipleTitle,
style: TextStyle(
color: context.colors.textPrimary,
fontSize: 16,
fontWeight: FontWeight.w600,
),
)),
Positioned(
left: 16,
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: Get.back,
child: SizedBox(
width: 44,
height: 44,
child: Center(
child: Image.asset(
'assets/images/common/ic_close.png',
width: 20,
height: 20,
color: context.colors.chartPurple,
),
),
),
),
),
],
),
),
Expanded(
child: ListView(
controller: scrollController,
physics: const ClampingScrollPhysics(),
padding: const EdgeInsets.fromLTRB(16, 8, 16, 20),
children: [
_InfoCard(
title: l10n.todayHrvPrincipleHowMeasureTitle,
children: [
_InfoText(
l10n.todayHrvPrincipleHowMeasureDescription1,
),
_InfoText(
l10n.todayHrvPrincipleHowMeasureDescription2,
),
_InfoText(
l10n.todayHrvPrincipleHowMeasureDescription3,
),
_InfoText(
l10n.todayHrvPrincipleHowMeasureDescription4,
),
const SizedBox(height: 16),
_StatusItem(
color: const Color(0xFFFF5279),
title: l10n.todayStressStatusOverload,
body: l10n.todayStressStatusOverloadDescription,
),
_StatusItem(
color: const Color(0xFFFF9A6E),
title: l10n.todayStressStatusCaution,
body: l10n.todayStressStatusCautionDescription,
),
_StatusItem(
color: const Color(0xFF7B9BFB),
title: l10n.todayStressStatusNormal,
body: l10n.todayStressStatusNormalDescription,
),
_StatusItem(
color: const Color(0xFF3BD49D),
title: l10n.todayStressStatusExcellent,
body: l10n.todayStressStatusExcellentDescription,
),
_StatusItem(
color: const Color(0xFFD9D9D9),
title: l10n.todayStressStatusInsufficientData,
body: l10n.todayStressStatusInsufficientDataDescription,
bottomSpacing: 0,
),
],
),
const SizedBox(height: 12),
const _FaqLinksCard(),
],
),
),
],
),
),
);
}
}
class _InfoCard extends StatelessWidget {
const _InfoCard({required this.title, required this.children});
final String title;
final List<Widget> children;
@override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: TextStyle(
color: context.colors.textPrimary,
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 12),
...children,
],
),
);
}
}
class _InfoText extends StatelessWidget {
const _InfoText(this.text);
final String text;
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(bottom: 3),
child: Text(
text,
style: TextStyle(
color: context.colors.textSecondary,
fontSize: 12,
height: 17 / 12,
fontWeight: FontWeight.w400,
),
),
);
}
}
class _StatusItem extends StatelessWidget {
const _StatusItem({
required this.color,
required this.title,
required this.body,
this.bottomSpacing = 12,
});
final Color color;
final String title;
final String body;
final double bottomSpacing;
@override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.only(bottom: bottomSpacing),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Container(
width: 12,
height: 12,
decoration: BoxDecoration(color: color, shape: BoxShape.circle),
),
const SizedBox(width: 5),
Text(
title,
style: TextStyle(
color: context.colors.textSecondary,
fontSize: 12,
height: 17 / 12,
fontWeight: FontWeight.w400,
),
),
],
),
const SizedBox(height: 2),
_InfoText(body),
],
),
);
}
}
class _FaqLinksCard extends StatelessWidget {
const _FaqLinksCard();
@override
Widget build(BuildContext context) {
final l10n = context.l10n;
return _InfoCard(
title: l10n.todayFaqSectionTitle,
children: [
_FaqLink(l10n.todayFaqLinkNoData),
_FaqLink(l10n.todayFaqLinkHrvRealtimeUpdate),
_FaqLink(l10n.todayFaqLinkWatchNoStatusAndInteractionNotification),
_FaqLink(l10n.todayFaqLinkWatchFaceDataDelay),
_FaqLink(l10n.todayFaqLinkWatchFaceBlackScreen),
],
);
}
}
class _FaqLink extends StatelessWidget {
const _FaqLink(this.text);
final String text;
@override
Widget build(BuildContext context) {
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: showTodayFaqBottomSheet,
child: Padding(
padding: const EdgeInsets.only(bottom: 14),
child: Text(
text,
style: TextStyle(
color: context.colors.textSecondary,
fontSize: 12,
height: 17 / 12,
fontWeight: FontWeight.w400,
decoration: TextDecoration.underline,
),
),
),
);
}
}
... ...
import 'package:doublefeel_flutter/core/theme/app_theme.dart';
import 'package:doublefeel_flutter/l10n/l10n_extensions.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'today_faq_bottom_sheet.dart';
void showRealtimeStressExplanationBottomSheet() {
Get.bottomSheet(
DraggableScrollableSheet(
initialChildSize: 0.96,
minChildSize: 0.2,
maxChildSize: 0.96,
expand: false,
snap: true,
builder: (context, scrollController) {
return RealtimeStressExplanationBottomSheet(
scrollController: scrollController,
);
},
),
barrierColor: Colors.black.withValues(alpha: 0.7),
enableDrag: true,
isScrollControlled: true,
persistent: false,
);
}
class RealtimeStressExplanationBottomSheet extends StatelessWidget {
const RealtimeStressExplanationBottomSheet({
super.key,
required this.scrollController,
});
final ScrollController scrollController;
@override
Widget build(BuildContext context) {
final l10n = context.l10n;
return Container(
decoration: const BoxDecoration(
color: Color(0xFFF5F2FF),
borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
),
child: SafeArea(
top: false,
child: Column(
children: [
SizedBox(
height: 64,
child: Stack(
alignment: Alignment.center,
children: [
Center(
child: Text(
l10n.todayRealtimeStressTitle,
style: TextStyle(
color: context.colors.textPrimary,
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
),
Positioned(
left: 16,
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: Get.back,
child: SizedBox(
width: 44,
height: 44,
child: Center(
child: Image.asset(
'assets/images/common/ic_close.png',
width: 20,
height: 20,
color: context.colors.chartPurple,
),
),
),
),
),
],
),
),
Expanded(
child: ListView(
controller: scrollController,
physics: const ClampingScrollPhysics(),
padding: const EdgeInsets.fromLTRB(16, 8, 16, 20),
children: [
_InfoCard(
title: l10n.todayRealtimeStressWhatTitle,
children: [
_InfoText(
l10n.todayRealtimeStressWhatDescription1,
),
_InfoText(l10n.todayRealtimeStressWhatDescription2),
_InfoText(l10n.todayRealtimeStressWhatDescription3),
],
),
const SizedBox(height: 12),
_InfoCard(
title: l10n.todayRealtimeStressDivisionTitle,
children: [
_InfoText(l10n.todayRealtimeStressDivisionIntro),
const SizedBox(height: 16),
_StatusItem(
color: const Color(0xFF3BD49D),
title: l10n.todayRealtimeStressExcellentRange,
body: l10n.todayRealtimeStressExcellentDescription,
),
_StatusItem(
color: const Color(0xFF7B9BFB),
title: l10n.todayRealtimeStressNormalRange,
body: l10n.todayRealtimeStressNormalDescription,
),
_StatusItem(
color: const Color(0xFFFF9A6E),
title: l10n.todayRealtimeStressCautionRange,
body: l10n.todayRealtimeStressCautionDescription,
),
_StatusItem(
color: const Color(0xFFFF5279),
title: l10n.todayRealtimeStressOverloadRange,
body: l10n.todayRealtimeStressOverloadDescription,
),
_InfoText(l10n.todayRealtimeStressDivisionBaseline),
_InfoText(l10n.todayRealtimeStressDivisionAwake),
],
),
const SizedBox(height: 12),
_InfoCard(
title: l10n.todayRealtimeStressLowBetterTitle,
children: [
_InfoText(l10n.todayRealtimeStressLowBetterNo),
_InfoText(l10n.todayRealtimeStressLowBetterType),
_InfoText(
l10n.todayRealtimeStressLowBetterExample,
),
_InfoText(
l10n.todayRealtimeStressLowBetterHighStress,
),
_InfoText(l10n.todayRealtimeStressLowBetterTrend),
],
),
const SizedBox(height: 12),
_InfoCard(
title: l10n.todayRealtimeStressScenarioTitle,
children: [
_InfoText(
l10n.todayRealtimeStressScenarioHrvDefault,
),
_InfoText(
l10n.todayRealtimeStressScenarioRegionLimit,
),
_InfoText(l10n.todayRealtimeStressScenarioIntro),
_InfoText(
l10n.todayRealtimeStressScenarioUpdateEvery6Min),
_InfoText(l10n.todayRealtimeStressScenarioTimely),
_InfoText(
l10n.todayRealtimeStressScenarioConsistentTrend),
_InfoText(l10n.todayRealtimeStressScenarioSummary),
],
),
const SizedBox(height: 12),
const _FaqLinksCard(),
],
),
),
],
),
),
);
}
}
class _InfoCard extends StatelessWidget {
const _InfoCard({
required this.title,
required this.children,
});
final String title;
final List<Widget> children;
@override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: TextStyle(
color: context.colors.textPrimary,
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 12),
...children,
],
),
);
}
}
class _InfoText extends StatelessWidget {
const _InfoText(this.text);
final String text;
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(bottom: 3),
child: Text(
text,
style: TextStyle(
color: context.colors.textSecondary,
fontSize: 12,
height: 17 / 12,
fontWeight: FontWeight.w400,
),
),
);
}
}
class _StatusItem extends StatelessWidget {
const _StatusItem({
required this.color,
required this.title,
required this.body,
});
final Color color;
final String title;
final String body;
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(bottom: 12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Container(
width: 12,
height: 12,
decoration: BoxDecoration(color: color, shape: BoxShape.circle),
),
const SizedBox(width: 5),
Text(
title,
style: TextStyle(
color: context.colors.textSecondary,
fontSize: 12,
height: 17 / 12,
fontWeight: FontWeight.w400,
),
),
],
),
const SizedBox(height: 2),
_InfoText(body),
],
),
);
}
}
class _FaqLinksCard extends StatelessWidget {
const _FaqLinksCard();
@override
Widget build(BuildContext context) {
final l10n = context.l10n;
return _InfoCard(
title: l10n.todayFaqSectionTitle,
children: [
_FaqLink(l10n.todayFaqLinkNoData),
_FaqLink(l10n.todayFaqLinkHrvRealtimeUpdate),
_FaqLink(l10n.todayFaqLinkWatchNoStatusNotification),
_FaqLink(l10n.todayFaqLinkWatchFaceDataDelay),
_FaqLink(l10n.todayFaqLinkWatchFaceBlackScreen),
],
);
}
}
class _FaqLink extends StatelessWidget {
const _FaqLink(this.text);
final String text;
@override
Widget build(BuildContext context) {
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: showTodayFaqBottomSheet,
child: Padding(
padding: const EdgeInsets.only(bottom: 14),
child: Text(
text,
style: TextStyle(
color: context.colors.textSecondary,
fontSize: 12,
height: 17 / 12,
fontWeight: FontWeight.w400,
decoration: TextDecoration.underline,
),
),
),
);
}
}
... ...
import 'package:doublefeel_flutter/core/theme/app_theme.dart';
import 'package:doublefeel_flutter/l10n/l10n_extensions.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'today_faq_bottom_sheet.dart';
void showStressStatusExplanationBottomSheet() {
Get.bottomSheet(
DraggableScrollableSheet(
initialChildSize: 0.96,
minChildSize: 0.2,
maxChildSize: 0.96,
expand: false,
snap: true,
builder: (context, scrollController) {
return StressStatusExplanationBottomSheet(
scrollController: scrollController,
);
},
),
barrierColor: Colors.black.withValues(alpha: 0.7),
enableDrag: true,
isScrollControlled: true,
persistent: false,
);
}
class StressStatusExplanationBottomSheet extends StatelessWidget {
const StressStatusExplanationBottomSheet({
super.key,
required this.scrollController,
});
final ScrollController scrollController;
@override
Widget build(BuildContext context) {
final l10n = context.l10n;
return Container(
decoration: const BoxDecoration(
color: Color(0xFFF5F2FF),
borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
),
child: SafeArea(
top: false,
child: Column(
children: [
SizedBox(
height: 64,
child: Stack(
alignment: Alignment.center,
children: [
Center(
child: Text(
l10n.todayStressStatusTitle,
style: TextStyle(
color: context.colors.textPrimary,
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
),
Positioned(
left: 16,
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: Get.back,
child: SizedBox(
width: 44,
height: 44,
child: Center(
child: Image.asset(
'assets/images/common/ic_close.png',
width: 20,
height: 20,
color: context.colors.chartPurple,
),
),
),
),
),
],
),
),
Expanded(
child: ListView(
controller: scrollController,
physics: const ClampingScrollPhysics(),
padding: const EdgeInsets.fromLTRB(16, 8, 16, 20),
children: [
_InfoCard(
title: l10n.todayStressStatusWhatTitle,
children: [
_InfoText(
l10n.todayStressStatusWhatDescription1,
),
_InfoText(
l10n.todayStressStatusWhatDescription2,
),
const SizedBox(height: 16),
_StatusItem(
color: const Color(0xFFFF5279),
title: l10n.todayStressStatusOverload,
body: l10n.todayStressStatusOverloadDescription,
),
_StatusItem(
color: const Color(0xFFFF9A6E),
title: l10n.todayStressStatusCaution,
body: l10n.todayStressStatusCautionDescription,
),
_StatusItem(
color: const Color(0xFF7B9BFB),
title: l10n.todayStressStatusNormal,
body: l10n.todayStressStatusNormalDescription,
),
_StatusItem(
color: const Color(0xFF3BD49D),
title: l10n.todayStressStatusExcellent,
body: l10n.todayStressStatusExcellentDescription,
),
_StatusItem(
color: const Color(0xFFD9D9D9),
title: l10n.todayStressStatusInsufficientData,
body: l10n.todayStressStatusInsufficientDataDescription,
bottomSpacing: 0,
),
],
),
const SizedBox(height: 12),
_InfoCard(
title: l10n.todayStressStatusWhyHrvTitle,
children: [
_InfoText(l10n.todayStressStatusWhyHrvDescription),
_InfoText(l10n.todayStressStatusUsually),
_InfoText(l10n.todayStressStatusHrvHigher),
_InfoText(l10n.todayStressStatusHrvLower),
_InfoText(l10n.todayStressStatusHrvChangesFast),
],
),
const SizedBox(height: 12),
_InfoCard(
title: l10n.todayStressStatusAppWatchDifferenceTitle,
children: [
_InfoText(l10n.todayStressStatusAppWatchDifferenceApp),
_InfoText(l10n.todayStressStatusAppWatchDifferenceWatch),
],
),
const SizedBox(height: 12),
_InfoCard(
title: l10n.todayStressStatusWaitingDataTitle,
children: [
_InfoText(l10n.todayStressStatusWaitingDataDescription1),
_InfoText(l10n.todayStressStatusWaitingDataDescription2),
_InfoText(l10n.todayStressStatusWaitingDataReasonsIntro),
_InfoText(l10n.todayStressStatusWaitingDataReason1),
_InfoText(l10n.todayStressStatusWaitingDataReason2),
_InfoText(l10n.todayStressStatusWaitingDataReason3),
_InfoText(l10n.todayStressStatusWaitingDataReason4),
],
),
const SizedBox(height: 12),
const _FaqLinksCard(),
],
),
),
],
),
),
);
}
}
class _InfoCard extends StatelessWidget {
const _InfoCard({
required this.title,
required this.children,
});
final String title;
final List<Widget> children;
@override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: TextStyle(
color: context.colors.textPrimary,
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 12),
...children,
],
),
);
}
}
class _InfoText extends StatelessWidget {
const _InfoText(this.text);
final String text;
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(bottom: 3),
child: Text(
text,
style: TextStyle(
color: context.colors.textSecondary,
fontSize: 12,
height: 17 / 12,
fontWeight: FontWeight.w400,
),
),
);
}
}
class _StatusItem extends StatelessWidget {
const _StatusItem({
required this.color,
required this.title,
required this.body,
this.bottomSpacing = 12,
});
final Color color;
final String title;
final String body;
final double bottomSpacing;
@override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.only(bottom: bottomSpacing),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Container(
width: 12,
height: 12,
decoration: BoxDecoration(color: color, shape: BoxShape.circle),
),
const SizedBox(width: 5),
Text(
title,
style: TextStyle(
color: context.colors.textSecondary,
fontSize: 12,
height: 17 / 12,
fontWeight: FontWeight.w400,
),
),
],
),
const SizedBox(height: 2),
_InfoText(body),
],
),
);
}
}
class _FaqLinksCard extends StatelessWidget {
const _FaqLinksCard();
@override
Widget build(BuildContext context) {
final l10n = context.l10n;
return _InfoCard(
title: l10n.todayFaqSectionTitle,
children: [
_FaqLink(l10n.todayFaqLinkNoData),
_FaqLink(l10n.todayFaqLinkHrvRealtimeUpdate),
_FaqLink(l10n.todayFaqLinkWatchNoStatusNotification),
_FaqLink(l10n.todayFaqLinkWatchFaceDataDelay),
_FaqLink(l10n.todayFaqLinkWatchFaceBlackScreen),
],
);
}
}
class _FaqLink extends StatelessWidget {
const _FaqLink(this.text);
final String text;
@override
Widget build(BuildContext context) {
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: showTodayFaqBottomSheet,
child: Padding(
padding: const EdgeInsets.only(bottom: 14),
child: Text(
text,
style: TextStyle(
color: context.colors.textSecondary,
fontSize: 12,
height: 17 / 12,
fontWeight: FontWeight.w400,
decoration: TextDecoration.underline,
),
),
),
);
}
}
... ...
import 'package:doublefeel_flutter/core/theme/app_theme.dart';
import 'package:doublefeel_flutter/l10n/l10n_extensions.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
void showTodayFaqBottomSheet() {
Get.bottomSheet(
DraggableScrollableSheet(
initialChildSize: 0.96,
minChildSize: 0.2,
maxChildSize: 0.96,
expand: false,
snap: true,
builder: (context, scrollController) {
return TodayFaqBottomSheet(
scrollController: scrollController,
);
},
),
barrierColor: Colors.black.withValues(alpha: 0.7),
enableDrag: true,
isScrollControlled: true,
persistent: false,
);
}
class TodayFaqBottomSheet extends StatelessWidget {
const TodayFaqBottomSheet({
super.key,
required this.scrollController,
});
final ScrollController scrollController;
@override
Widget build(BuildContext context) {
final l10n = context.l10n;
return Container(
decoration: const BoxDecoration(
color: Color(0xFFF5F2FF),
borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
),
child: SafeArea(
top: false,
child: Column(
children: [
SizedBox(
height: 64,
child: Stack(
alignment: Alignment.center,
children: [
Center(
child: Text(
l10n.todayFaqTitle,
style: TextStyle(
color: context.colors.textPrimary,
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
),
Positioned(
left: 16,
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: Get.back,
child: SizedBox(
width: 44,
height: 44,
child: Center(
child: Image.asset(
'assets/images/common/ic_close.png',
width: 20,
height: 20,
color: context.colors.chartPurple,
),
),
),
),
),
],
),
),
Expanded(
child: ListView(
controller: scrollController,
physics: const ClampingScrollPhysics(),
padding: const EdgeInsets.fromLTRB(16, 8, 16, 20),
children: [
_InfoCard(
title: l10n.todayFaqNoDataTitle,
children: [
_InfoText(
l10n.todayFaqNoDataDescription1,
),
_InfoText(
l10n.todayFaqNoDataDescription2,
),
_InfoText(l10n.todayFaqNoDataDescription3),
const SizedBox(height: 8),
const _ContactText(),
],
),
const SizedBox(height: 12),
_InfoCard(
title: l10n.todayFaqWatchNoNotificationTitle,
children: [
_InfoText(
l10n.todayFaqWatchNoNotificationDescription1,
),
_InfoText(
l10n.todayFaqWatchNoNotificationDescription2,
),
_InfoText(
l10n.todayFaqWatchNoNotificationCheckPhoneNotification,
),
_InfoText(
l10n.todayFaqWatchNoNotificationCheckPhoneBackgroundRefresh,
),
_InfoText(
l10n.todayFaqWatchNoNotificationCheckWatchBackgroundRefresh,
),
_InfoText(l10n.todayFaqWatchNoNotificationCheckModes),
_InfoText(l10n.todayFaqWatchNoNotificationReinstall),
const SizedBox(height: 8),
const _ContactText(),
],
),
const SizedBox(height: 12),
_InfoCard(
title: l10n.todayFaqWatchFaceDelayTitle,
children: [
_InfoText(
l10n.todayFaqWatchFaceDelayDescription1,
),
_InfoText(l10n.todayFaqWatchFaceDelayIfOverOneHour),
_InfoText(l10n.todayFaqWatchFaceDelayOpenWatchApp),
_InfoText(l10n.todayFaqWatchFaceDelayIfStill),
_InfoText(l10n.todayFaqWatchFaceDelayRestartApp),
_InfoText(l10n.todayFaqWatchFaceDelayCheckIntro),
_InfoText(l10n.todayFaqWatchFaceDelayCheckData),
_InfoText(l10n.todayFaqWatchFaceDelayCheckPhoneHealth),
_InfoText(l10n.todayFaqWatchFaceDelayCheckWatchHealth),
_InfoText(
l10n.todayFaqWatchFaceDelayCheckBackgroundRefresh,
),
_InfoText(l10n.todayFaqWatchFaceDelayRestartWatch),
],
),
const SizedBox(height: 12),
_InfoCard(
title: l10n.todayFaqWatchFaceBlackScreenTitle,
children: [
_InfoText(
l10n.todayFaqWatchFaceBlackScreenDescription,
),
],
),
],
),
),
],
),
),
);
}
}
class _InfoCard extends StatelessWidget {
const _InfoCard({
required this.title,
required this.children,
});
final String title;
final List<Widget> children;
@override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: TextStyle(
color: context.colors.textPrimary,
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 12),
...children,
],
),
);
}
}
class _InfoText extends StatelessWidget {
const _InfoText(this.text);
final String text;
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(bottom: 3),
child: Text(
text,
style: TextStyle(
color: context.colors.textSecondary,
fontSize: 12,
height: 17 / 12,
fontWeight: FontWeight.w400,
),
),
);
}
}
class _ContactText extends StatelessWidget {
const _ContactText();
@override
Widget build(BuildContext context) {
final l10n = context.l10n;
return RichText(
text: TextSpan(
style: TextStyle(
color: context.colors.textSecondary,
fontSize: 12,
height: 17 / 12,
fontWeight: FontWeight.w400,
),
children: [
TextSpan(text: l10n.todayFaqContactPrefix),
TextSpan(
text: l10n.todayFaqContactAction,
style: TextStyle(
color: context.colors.primary,
fontWeight: FontWeight.w600,
decoration: TextDecoration.underline,
),
),
TextSpan(text: l10n.todayFaqContactSuffix),
],
),
);
}
}
... ...
... ... @@ -4,6 +4,8 @@ import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../../controllers/today_controller.dart';
import 'hrv_principle_explanation_bottom_sheet.dart';
import 'realtime_stress_explanation_bottom_sheet.dart';
// X轴:动态时间
// 一天以6小时为一个刻度划分
... ... @@ -56,7 +58,15 @@ class TodayHrvChartCard extends GetView<TodayController> {
),
),
const SizedBox(width: 4),
const Icon(Icons.info_outline, size: 14, color: _h3),
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: showRealtimeStressExplanationBottomSheet,
child: const SizedBox(
width: 26,
height: 26,
child: Icon(Icons.info_outline, size: 14, color: _h3),
),
),
const Spacer(),
],
),
... ... @@ -85,11 +95,21 @@ class TodayHrvChartCard extends GetView<TodayController> {
),
),
const SizedBox(width: 4),
Image.asset(
'assets/images/common/ic_info.png',
width: 14,
height: 14,
color: context.colors.textTertiary,
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: showHrvPrincipleExplanationBottomSheet,
child: SizedBox(
width: 26,
height: 26,
child: Center(
child: Image.asset(
'assets/images/common/ic_info.png',
width: 14,
height: 14,
color: context.colors.textTertiary,
),
),
),
),
const Spacer(),
Text(
... ...
... ... @@ -42,7 +42,7 @@ class AppColors {
// ==========================================
static const backgroundLight = Color(0xFFFAFAFE);
static const brandBackgroundLight = Color(0xFFEAE3FF);
static const warning = Color(0xFFFC4447);
// ==========================================
// 渐变基础色 (Gradient Components)
// ==========================================
... ...
... ... @@ -34,6 +34,8 @@ class AppColorsExtension extends ThemeExtension<AppColorsExtension> {
// Gradients
final LinearGradient brandBackgroundGradient;
final Color warning;
const AppColorsExtension({
required this.primary,
required this.textPrimary,
... ... @@ -53,6 +55,7 @@ class AppColorsExtension extends ThemeExtension<AppColorsExtension> {
required this.backgroundLight,
required this.brandBackgroundLight,
required this.brandBackgroundGradient,
required this.warning,
});
/// The standard light palette derived directly from Figma.
... ... @@ -80,6 +83,7 @@ class AppColorsExtension extends ThemeExtension<AppColorsExtension> {
begin: Alignment.centerLeft,
end: Alignment.centerRight,
),
warning: Color(0xFFFC4447),
);
}
... ... @@ -108,6 +112,7 @@ class AppColorsExtension extends ThemeExtension<AppColorsExtension> {
begin: Alignment.centerLeft,
end: Alignment.centerRight,
),
warning: AppColors.warning,
);
}
... ... @@ -131,6 +136,7 @@ class AppColorsExtension extends ThemeExtension<AppColorsExtension> {
Color? backgroundLight,
Color? brandBackgroundLight,
LinearGradient? brandBackgroundGradient,
Color? warning,
}) {
return AppColorsExtension(
primary: primary ?? this.primary,
... ... @@ -150,7 +156,9 @@ class AppColorsExtension extends ThemeExtension<AppColorsExtension> {
vipPurple: vipPurple ?? this.vipPurple,
backgroundLight: backgroundLight ?? this.backgroundLight,
brandBackgroundLight: brandBackgroundLight ?? this.brandBackgroundLight,
brandBackgroundGradient: brandBackgroundGradient ?? this.brandBackgroundGradient,
brandBackgroundGradient:
brandBackgroundGradient ?? this.brandBackgroundGradient,
warning: warning ?? this.warning,
);
}
... ... @@ -176,8 +184,11 @@ class AppColorsExtension extends ThemeExtension<AppColorsExtension> {
vipGold: Color.lerp(vipGold, other.vipGold, t)!,
vipPurple: Color.lerp(vipPurple, other.vipPurple, t)!,
backgroundLight: Color.lerp(backgroundLight, other.backgroundLight, t)!,
brandBackgroundLight: Color.lerp(brandBackgroundLight, other.brandBackgroundLight, t)!,
brandBackgroundGradient: LinearGradient.lerp(brandBackgroundGradient, other.brandBackgroundGradient, t)!,
brandBackgroundLight:
Color.lerp(brandBackgroundLight, other.brandBackgroundLight, t)!,
brandBackgroundGradient: LinearGradient.lerp(
brandBackgroundGradient, other.brandBackgroundGradient, t)!,
warning: Color.lerp(warning, other.warning, t)!,
);
}
}
... ...
... ... @@ -85,7 +85,6 @@
"onboardingResearchHealthy": "Feeling Great",
"onboardingResearchPoorSleep": "Poor Sleep",
"onboardingResearchGoodSleep": "Good Sleep",
"loginSlogan": "Start your pressure alert and health companion journey\nso love and care are always present",
"loginWithPhone": "Sign in with Phone",
"loginWithApple": "Sign in with Apple",
... ... @@ -94,7 +93,6 @@
"loginTerms": "Terms of Service",
"loginAgreementAnd": " and ",
"loginPrivacy": "Privacy Policy",
"phoneLoginHello": "Hello",
"phoneLoginWelcome": "Welcome to Double Feel",
"phoneLoginPhoneHint": "Enter phone number",
... ... @@ -105,13 +103,126 @@
"phoneLoginCodeHint": "Enter verification code",
"phoneLoginAutoRegisterHint": "Unregistered numbers will be registered automatically",
"phoneLoginLoggingIn": "Signing in...",
"loginAgreeToTermsToast": "Please read and agree to the Terms of Service and Privacy Policy first",
"phoneLoginInvalidPhone": "Invalid phone number",
"phoneLoginCodeSentSuccess": "Code sent",
"phoneLoginInvalidCode": "Invalid verification code",
"todayHealthDataAuthTitle": "Unable to access heart rate health data",
"todayHealthDataAuthDescription": "DoubleFeel needs permission to access your health data to provide stress reminders, real-time stress statistics, and health suggestions. Otherwise, some app features may not work properly. Your health data is stored locally only and will not be uploaded to any server.",
"todayHealthDataAuthAction": "Authorize health data access"
"todayHealthDataAuthAction": "Authorize health data access",
"measureYourHrvNow": "Measure your HRV now",
"todayBottomSheetGotIt": "Got it",
"todayFaqTitle": "FAQ",
"todayFaqSectionTitle": "DoubleFeel FAQ",
"todayFaqLinkNoData": "What if the app or watch face has no data?",
"todayFaqLinkHrvRealtimeUpdate": "How can HRV data update in real time?",
"todayFaqLinkWatchNoStatusNotification": "Why can't my watch receive status notifications?",
"todayFaqLinkWatchNoStatusAndInteractionNotification": "Why can't my watch receive status and interaction notifications?",
"todayFaqLinkWatchFaceDataDelay": "Why is watch face data delayed or not updating?",
"todayFaqLinkWatchFaceBlackScreen": "Why does the watch face turn black?",
"todayStressStatusTitle": "Overall stress status",
"todayHrvPrincipleTitle": "How HRV is measured",
"todayRealtimeStressTitle": "How real-time stress works",
"todayStressStatusOverload": "Stress overload",
"todayStressStatusCaution": "Stress warning",
"todayStressStatusNormal": "Normal",
"todayStressStatusExcellent": "Excellent",
"todayStressStatusInsufficientData": "Insufficient data",
"todayStressStatusOverloadDescription": "Your current HRV is much lower than your long-term average, which may indicate fatigue, high stress, or insufficient recovery. Rest is recommended.",
"todayStressStatusCautionDescription": "Your current HRV is below the normal range, and your body may be accumulating stress. Pay attention to rest and recovery.",
"todayStressStatusNormalDescription": "Your current body state is within your normal fluctuation range.",
"todayStressStatusExcellentDescription": "Your current HRV is higher than your recent average, indicating better recovery and overall state.",
"todayStressStatusInsufficientDataDescription": "There is not enough available data to accurately assess your stress state yet.",
"todayHrvMeasurementIntro": "Apple Watch measures HRV every 2-5 hours by default. If you want to measure it manually right now, follow these steps:",
"todayHrvMeasurementStep1": "1. Wear your Apple Watch snugly, sit down, and stay calm",
"todayHrvMeasurementStep2": "2. Open Mindfulness on Apple Watch and start Breathe",
"todayHrvMeasurementStep3": "3. Keep breathing steadily and wait 1-3 minutes",
"todayHrvMeasurementStep4": "4. After breathing is complete, lock and unlock your iPhone once",
"todayHrvMeasurementStep5": "5. Wait about one minute. StressWatch will receive and display your data",
"todayHrvMeasurementHint": "Tip: Data comes from Apple Watch. After measurement, there may be delays or data may not sync immediately. If this happens, measure again and wait for the data to be read.",
"todayHrvMeasurementWarning": "Note: Health permissions must be enabled, and Low Power Mode must be turned off.",
"todayStressStatusWhatTitle": "What is overall stress status?",
"todayStressStatusWhatDescription1": "DoubleFeel combines your HRV (heart rate variability), resting heart rate, and body-state changes from the past 30 days to assess your overall stress level.",
"todayStressStatusWhatDescription2": "Because HRV fluctuates with emotions, exercise, sleep, and fatigue, a single reading has limited value. We recommend focusing on your overall stress status across the day, which is more stable and useful. It helps you understand your body state and helps close contacts notice changes in time.",
"todayStressStatusWhyHrvTitle": "Why use HRV (heart rate variability)?",
"todayStressStatusWhyHrvDescription": "HRV is an important metric for measuring body stress and recovery capacity.",
"todayStressStatusUsually": "In general:",
"todayStressStatusHrvHigher": "· Higher HRV usually means better recovery",
"todayStressStatusHrvLower": "· Lower HRV may indicate fatigue, stress, or insufficient sleep",
"todayStressStatusHrvChangesFast": "· HRV changes quickly, making it useful for short-term body-state changes.",
"todayStressStatusAppWatchDifferenceTitle": "How are stress statuses on the phone app and Apple Watch different?",
"todayStressStatusAppWatchDifferenceApp": "The phone app home page shows the day's overall stress status, combining HRV, resting heart rate, and overall trends.",
"todayStressStatusAppWatchDifferenceWatch": "Apple Watch shows the most recent real-time stress status, which is better for quickly checking your current body changes.",
"todayStressStatusWaitingDataTitle": "Why does Waiting for data appear?",
"todayStressStatusWaitingDataDescription1": "Waiting for data means the current amount of collected data is not enough to generate a reliable stress assessment.",
"todayStressStatusWaitingDataDescription2": "Please keep wearing your Apple Watch and wait for the system to collect data automatically.",
"todayStressStatusWaitingDataReasonsIntro": "Possible reasons include:",
"todayStressStatusWaitingDataReason1": "1. Not enough HRV samples",
"todayStressStatusWaitingDataReason2": "2. Missing resting heart rate data",
"todayStressStatusWaitingDataReason3": "3. Apple Watch has not been worn long enough",
"todayStressStatusWaitingDataReason4": "4. Apple Health permissions are not enabled",
"todayHrvPrincipleHowMeasureTitle": "How does DoubleFeel measure stress status?",
"todayHrvPrincipleHowMeasureDescription1": "When you wear Apple Watch normally, the system automatically collects your heart rate data and syncs it to Apple Health.",
"todayHrvPrincipleHowMeasureDescription2": "DoubleFeel calculates HRV (heart rate variability) indicators based on this data to assess your body stress and recovery state.",
"todayHrvPrincipleHowMeasureDescription3": "HRV is sensitive to stress, fatigue, sleep, emotions, and recovery, so it helps us notice body-state changes earlier.",
"todayHrvPrincipleHowMeasureDescription4": "To make results more accurate, DoubleFeel compares your current HRV state with your own 30-day average instead of comparing it directly with other people.",
"todayRealtimeStressWhatTitle": "What is real-time stress?",
"todayRealtimeStressWhatDescription1": "Real-time stress is a body stress indicator dynamically generated by DoubleFeel based on your current HRV, heart rate state, and changes in your personal history.",
"todayRealtimeStressWhatDescription2": "A higher stress value means your body state is deviating more from your usual baseline and may reflect fatigue, insufficient recovery, or high stress.",
"todayRealtimeStressWhatDescription3": "It helps you notice body changes faster and adjust rest, exercise, and daily rhythm in time.",
"todayRealtimeStressDivisionTitle": "How is real-time stress divided?",
"todayRealtimeStressDivisionIntro": "Real-time stress is shown as a percentage:",
"todayRealtimeStressExcellentRange": "Excellent: 1%-20%",
"todayRealtimeStressNormalRange": "Normal: 21%-60%",
"todayRealtimeStressCautionRange": "Stress warning: 61%-80%",
"todayRealtimeStressOverloadRange": "Stress overload: 81%-100%",
"todayRealtimeStressExcellentDescription": "Your recovery state is good and you are generally relaxed.",
"todayRealtimeStressNormalDescription": "Your body is within the normal fluctuation range.",
"todayRealtimeStressCautionDescription": "Your body may be accumulating stress and needs proper rest and recovery.",
"todayRealtimeStressOverloadDescription": "Your body stress is clearly high. Reduce load and pay attention to sleep and recovery.",
"todayRealtimeStressDivisionBaseline": "These ranges are adjusted dynamically based on your personal baseline and should not be directly compared between users.",
"todayRealtimeStressDivisionAwake": "Real-time stress mainly reflects body stress changes while awake.",
"todayRealtimeStressLowBetterTitle": "Is lower real-time stress always better?",
"todayRealtimeStressLowBetterNo": "Not necessarily.",
"todayRealtimeStressLowBetterType": "Body stress can be normal or abnormal.",
"todayRealtimeStressLowBetterExample": "For example, real-time stress rising briefly during or after exercise is a normal recovery response. It can also rise temporarily during focused work or emotional excitement, which are normal body adjustments.",
"todayRealtimeStressLowBetterHighStress": "But if stress remains high while resting, sitting for a long time, or after poor sleep, it may indicate physical fatigue, mental stress, insufficient sleep recovery, incomplete exercise recovery, too much caffeine, alcohol, stimulants, or possible discomfort.",
"todayRealtimeStressLowBetterTrend": "DoubleFeel focuses more on your long-term trend than on a single fluctuation.",
"todayRealtimeStressScenarioTitle": "When should HRV and real-time stress be used?",
"todayRealtimeStressScenarioHrvDefault": "With Apple Watch default settings, HRV updates every 2-5 hours.",
"todayRealtimeStressScenarioRegionLimit": "In some regions, Apple Watch breathing features may be limited, which can affect HRV update frequency. Turning on breathing features may also consume more battery.",
"todayRealtimeStressScenarioIntro": "To address the long interval between HRV updates, DoubleFeel designed real-time stress:",
"todayRealtimeStressScenarioUpdateEvery6Min": "· Real-time stress updates every 6 minutes",
"todayRealtimeStressScenarioTimely": "· It can reflect body-state changes more promptly",
"todayRealtimeStressScenarioConsistentTrend": "· In most cases, the real-time stress trend is consistent with the HRV trend",
"todayRealtimeStressScenarioSummary": "This lets users see long-term HRV trends while also using real-time stress as a short-term body-state reference.",
"todayFaqNoDataTitle": "What if the app or watch face has no data?",
"todayFaqNoDataDescription1": "1. Confirm that Apple Watch is on watchOS 10.0 or above and iPhone is on iOS 14 or above. You can check system versions in About.",
"todayFaqNoDataDescription2": "2. Confirm all permissions are enabled: iPhone Health > Sharing > Apps > DoubleFeel > Turn On All Permissions.",
"todayFaqNoDataDescription3": "3. Confirm the device is not in Low Power Mode, low battery, or worn too loosely, as these can affect data collection.",
"todayFaqContactPrefix": "If everything above is correct, you can ",
"todayFaqContactAction": "contact us",
"todayFaqContactSuffix": ".",
"todayFaqWatchNoNotificationTitle": "Watch cannot receive status notifications?",
"todayFaqWatchNoNotificationDescription1": "Apple Watch and iPhone notifications have priority rules: when your iPhone is unlocked and the screen is on, notifications only appear on the phone and will not appear on the watch.",
"todayFaqWatchNoNotificationDescription2": "If stress data displays and updates normally but your watch does not receive notifications, try the following:",
"todayFaqWatchNoNotificationCheckPhoneNotification": "1. Check whether iPhone notifications are enabled (Settings > DoubleFeel > Notifications).",
"todayFaqWatchNoNotificationCheckPhoneBackgroundRefresh": "2. Check whether iPhone Background App Refresh is enabled (Settings > DoubleFeel > Background App Refresh).",
"todayFaqWatchNoNotificationCheckWatchBackgroundRefresh": "3. Check whether Apple Watch Background App Refresh is enabled (Settings > General > Background App Refresh, and make sure DoubleFeel is enabled).",
"todayFaqWatchNoNotificationCheckModes": "4. Make sure Low Power, Focus, Do Not Disturb, Theater, Sleep, and similar modes are off.",
"todayFaqWatchNoNotificationReinstall": "5. Reinstall DoubleFeel and restart Apple Watch and iPhone.",
"todayFaqWatchFaceDelayTitle": "Watch face data not updating or delayed?",
"todayFaqWatchFaceDelayDescription1": "Due to Apple system limits, all watch faces, third-party or official, may have delays from a few minutes to half an hour. Developers cannot control the refresh frequency.",
"todayFaqWatchFaceDelayIfOverOneHour": "If the phone data refreshes but the watch face still has not updated after more than 1 hour:",
"todayFaqWatchFaceDelayOpenWatchApp": "Manually open DoubleFeel on Apple Watch and wait about 1 minute.",
"todayFaqWatchFaceDelayIfStill": "If it still does not update:",
"todayFaqWatchFaceDelayRestartApp": "Close the DoubleFeel background process and restart it.",
"todayFaqWatchFaceDelayCheckIntro": "If it still does not work, check:",
"todayFaqWatchFaceDelayCheckData": "· Whether both phone and watch apps can show HRV data normally.",
"todayFaqWatchFaceDelayCheckPhoneHealth": "· Make sure all permissions are enabled on iPhone: iOS Settings > Privacy & Security > Health > DoubleFeel.",
"todayFaqWatchFaceDelayCheckWatchHealth": "· Make sure all permissions are enabled on Apple Watch: Settings > Health > Data Sources & Access > DoubleFeel.",
"todayFaqWatchFaceDelayCheckBackgroundRefresh": "· Confirm DoubleFeel is enabled in Apple Watch > Settings > General > Background App Refresh.",
"todayFaqWatchFaceDelayRestartWatch": "· If it still does not refresh automatically, restart Apple Watch. Long runtimes or high background usage may cause watch face updates to pause.",
"todayFaqWatchFaceBlackScreenTitle": "Watch face turns black?",
"todayFaqWatchFaceBlackScreenDescription": "If the custom interactive watch face turns black after being added and only shows time and date, long-press the watch face, tap Edit, swipe left to Complications, choose DoubleFeel, and add each component again as needed."
}
... ...
... ... @@ -88,63 +88,224 @@
"onboardingResearchHealthy": "身体倍儿棒",
"onboardingResearchPoorSleep": "睡眠不足",
"onboardingResearchGoodSleep": "睡眠充足",
"loginSlogan": "开启压力预警与健康陪伴之旅\n让爱与关心从不缺席",
"@loginSlogan": { "description": "登录页 slogan" },
"@loginSlogan": {
"description": "登录页 slogan"
},
"loginWithPhone": "手机号登录/注册",
"@loginWithPhone": { "description": "手机号登录按钮" },
"@loginWithPhone": {
"description": "手机号登录按钮"
},
"loginWithApple": "通过Apple登录",
"@loginWithApple": { "description": "Apple登录按钮" },
"@loginWithApple": {
"description": "Apple登录按钮"
},
"loginLastUsed": "上次使用",
"@loginLastUsed": { "description": "上次使用标签" },
"@loginLastUsed": {
"description": "上次使用标签"
},
"loginAgreementPrefix": "我已阅读并同意",
"@loginAgreementPrefix": { "description": "协议勾选前缀" },
"@loginAgreementPrefix": {
"description": "协议勾选前缀"
},
"loginTerms": "用户协议",
"@loginTerms": { "description": "用户协议链接" },
"@loginTerms": {
"description": "用户协议链接"
},
"loginAgreementAnd": "与",
"@loginAgreementAnd": { "description": "协议连接词" },
"@loginAgreementAnd": {
"description": "协议连接词"
},
"loginPrivacy": "隐私协议",
"@loginPrivacy": { "description": "隐私协议链接" },
"@loginPrivacy": {
"description": "隐私协议链接"
},
"phoneLoginHello": "Hello~",
"@phoneLoginHello": { "description": "手机号登录页打招呼" },
"@phoneLoginHello": {
"description": "手机号登录页打招呼"
},
"phoneLoginWelcome": "欢迎来到 Double Feel",
"@phoneLoginWelcome": { "description": "手机号登录页欢迎语" },
"@phoneLoginWelcome": {
"description": "手机号登录页欢迎语"
},
"phoneLoginPhoneHint": "请输入手机号",
"@phoneLoginPhoneHint": { "description": "手机号输入框占位符" },
"@phoneLoginPhoneHint": {
"description": "手机号输入框占位符"
},
"phoneLoginSendCode": "发送验证码",
"@phoneLoginSendCode": { "description": "发送验证码按钮(首次)" },
"@phoneLoginSendCode": {
"description": "发送验证码按钮(首次)"
},
"phoneLoginSending": "发送中",
"@phoneLoginSending": { "description": "发送验证码按钮(请求中)" },
"@phoneLoginSending": {
"description": "发送验证码按钮(请求中)"
},
"phoneLoginSentCountdown": "已发送 {countdown}s",
"@phoneLoginSentCountdown": {
"description": "倒计时文案",
"placeholders": {
"countdown": { "type": "int" }
"countdown": {
"type": "int"
}
}
},
"phoneLoginResend": "重新发送",
"@phoneLoginResend": { "description": "倒计时结束后重新发送按钮" },
"@phoneLoginResend": {
"description": "倒计时结束后重新发送按钮"
},
"phoneLoginCodeHint": "请输入验证码",
"@phoneLoginCodeHint": { "description": "验证码输入框占位符" },
"@phoneLoginCodeHint": {
"description": "验证码输入框占位符"
},
"phoneLoginAutoRegisterHint": "未注册的手机号验证通过后将自动注册",
"@phoneLoginAutoRegisterHint": { "description": "自动注册提示" },
"@phoneLoginAutoRegisterHint": {
"description": "自动注册提示"
},
"phoneLoginLoggingIn": "登录中...",
"@phoneLoginLoggingIn": { "description": "登录按钮 loading 文案" },
"@phoneLoginLoggingIn": {
"description": "登录按钮 loading 文案"
},
"loginAgreeToTermsToast": "请先阅读并同意《用户协议》与《隐私协议》",
"@loginAgreeToTermsToast": { "description": "未勾选协议时的 toast" },
"@loginAgreeToTermsToast": {
"description": "未勾选协议时的 toast"
},
"phoneLoginInvalidPhone": "手机号格式错误",
"@phoneLoginInvalidPhone": { "description": "手机号格式错误 toast" },
"@phoneLoginInvalidPhone": {
"description": "手机号格式错误 toast"
},
"phoneLoginCodeSentSuccess": "发送成功",
"@phoneLoginCodeSentSuccess": { "description": "验证码发送成功 toast" },
"@phoneLoginCodeSentSuccess": {
"description": "验证码发送成功 toast"
},
"phoneLoginInvalidCode": "验证码格式错误",
"@phoneLoginInvalidCode": { "description": "验证码格式错误 toast" },
"@phoneLoginInvalidCode": {
"description": "验证码格式错误 toast"
},
"todayHealthDataAuthTitle": "无法获取心率健康数据",
"@todayHealthDataAuthTitle": { "description": "今日页健康数据授权卡片标题" },
"@todayHealthDataAuthTitle": {
"description": "今日页健康数据授权卡片标题"
},
"todayHealthDataAuthDescription": "DoubleFeel 需要授权访问你的健康数据,才能提供压力提醒、实时压力统计和健康建议;否则应用功能可能无法正常使用。请放心,你的健康数据仅存储在本地,不会上传到任何服务器。",
"@todayHealthDataAuthDescription": { "description": "今日页健康数据授权卡片说明" },
"@todayHealthDataAuthDescription": {
"description": "今日页健康数据授权卡片说明"
},
"todayHealthDataAuthAction": "授权访问健康数据",
"@todayHealthDataAuthAction": { "description": "今日页健康数据授权卡片按钮文案" }
"@todayHealthDataAuthAction": {
"description": "今日页健康数据授权卡片按钮文案"
},
"measureYourHrvNow": "立即测量HRV",
"todayBottomSheetGotIt": "我知道了",
"todayFaqTitle": "常见问题",
"todayFaqSectionTitle": "DoubleFeel 常见问题",
"todayFaqLinkNoData": "APP或表盘有没有数据怎么办?",
"todayFaqLinkHrvRealtimeUpdate": "HRV数据如何实时更新?",
"todayFaqLinkWatchNoStatusNotification": "手表为什么无法收到状态通知?",
"todayFaqLinkWatchNoStatusAndInteractionNotification": "手表为什么无法收到状态和互动通知?",
"todayFaqLinkWatchFaceDataDelay": "手表表盘数据不更新或者有延迟?",
"todayFaqLinkWatchFaceBlackScreen": "手表表盘为什么会出现黑屏?",
"todayStressStatusTitle": "综合压力状态说明",
"todayHrvPrincipleTitle": "HRV测量原理",
"todayRealtimeStressTitle": "实时压力原理",
"todayStressStatusOverload": "压力过载",
"todayStressStatusCaution": "注意压力",
"todayStressStatusNormal": "状态正常",
"todayStressStatusExcellent": "状态优秀",
"todayStressStatusInsufficientData": "数据不足",
"todayStressStatusOverloadDescription": "当前 HRV 明显低于你的长期平均水平,可能意味着身体疲劳、压力过高或恢复不足。建议及时休息。",
"todayStressStatusCautionDescription": "当前 HRV 低于正常范围,身体可能正在积累压力,需要注意作息与恢复。",
"todayStressStatusNormalDescription": "当前身体状态处于你的正常波动范围内。",
"todayStressStatusExcellentDescription": "当前 HRV 高于近期平均水平,代表身体恢复与整体状态较好。",
"todayStressStatusInsufficientDataDescription": "当前可用数据不足,暂时无法准确判断压力状态。",
"todayHrvMeasurementIntro": "AppleWatch默认每2-5小时测量一次HRV,如果你希望立即手动进行测量,可以参考以下方法:",
"todayHrvMeasurementStep1": "1、戴紧AppleWatch,坐下来,保持心境平和",
"todayHrvMeasurementStep2": "2、打开AppleWatch上的「正念」里的「呼吸」",
"todayHrvMeasurementStep3": "3、保持平稳的呼吸,等待1-3分钟",
"todayHrvMeasurementStep4": "4、完成呼吸后,锁屏一次再解锁你的iPhone",
"todayHrvMeasurementStep5": "5、等待一分钟左右,StressWatch会收到你的数据并展示",
"todayHrvMeasurementHint": "提示:数据源来自AppleWatch,在测量之后可能存在延迟或是数据未能同步的情况。如若出现上述情况,请重新测量并等待数据读取。",
"todayHrvMeasurementWarning": "注意:需打开健康里的权限,同时关闭省电模式。",
"todayStressStatusWhatTitle": "什么是综合压力状态?",
"todayStressStatusWhatDescription1": "DoubleFeel 会结合你过去 30 天的 HRV(心率变异性)、静息心率以及当天的身体状态变化,综合评估你的整体压力水平。",
"todayStressStatusWhatDescription2": "由于 HRV 会随着情绪、运动、睡眠和疲劳不断波动,单次数据参考意义有限,因此我们更建议关注一整天的综合压力状态,让结果更稳定、更有参考价值。综合压力不仅能帮助你了解自己的身体状态,也能让亲密联系人更及时地关注你的变化。",
"todayStressStatusWhyHrvTitle": "为什么要参考 HRV(心率变异性)?",
"todayStressStatusWhyHrvDescription": "HRV 是衡量身体压力与恢复能力的重要指标。",
"todayStressStatusUsually": "通常来说:",
"todayStressStatusHrvHigher": "· HRV 越高,代表身体恢复状态越好",
"todayStressStatusHrvLower": "· HRV 越低,可能意味着疲劳、压力或睡眠不足",
"todayStressStatusHrvChangesFast": "· HRV 变化较快,更适合观察短时间内的身体状态变化。",
"todayStressStatusAppWatchDifferenceTitle": "手机 App 与 Apple Watch 显示的压力状态有什么区别?",
"todayStressStatusAppWatchDifferenceApp": "手机 App 首页显示的是当天的综合压力状态,会综合分析 HRV、静息心率与整体趋势。",
"todayStressStatusAppWatchDifferenceWatch": "Apple Watch 显示的是最近一次的实时压力状态,更适合快速查看当前身体变化。",
"todayStressStatusWaitingDataTitle": "为什么会出现“等待数据”?",
"todayStressStatusWaitingDataDescription1": "“等待数据”代表当前采集到的数据量不足,暂时无法生成可靠的压力评估。",
"todayStressStatusWaitingDataDescription2": "请继续佩戴 Apple Watch,等待系统自动采集数据。",
"todayStressStatusWaitingDataReasonsIntro": "可能原因包括:",
"todayStressStatusWaitingDataReason1": "1. HRV 数据采样不足",
"todayStressStatusWaitingDataReason2": "2. 缺少静息心率数据",
"todayStressStatusWaitingDataReason3": "3. Apple Watch 佩戴时间较短",
"todayStressStatusWaitingDataReason4": "4. Apple Health 权限未开启",
"todayHrvPrincipleHowMeasureTitle": "DoubleFeel 如何测量压力状态?",
"todayHrvPrincipleHowMeasureDescription1": "当你正常佩戴 Apple Watch 时,系统会自动采集你的心率数据,并同步至 Apple Health。",
"todayHrvPrincipleHowMeasureDescription2": "DoubleFeel 会基于这些数据计算 HRV(心率变异性)相关指标,用于评估你的身体压力与恢复状态。",
"todayHrvPrincipleHowMeasureDescription3": "HRV 对压力、疲劳、睡眠、情绪与身体恢复都非常敏感,因此它能够帮助我们更早发现身体状态变化。",
"todayHrvPrincipleHowMeasureDescription4": "为了让结果更准确,DoubleFeel 会将你当前的 HRV 状态与过去 30 天的个人平均水平进行对比,而不是直接与其他人比较。",
"todayRealtimeStressWhatTitle": "什么是实时压力?",
"todayRealtimeStressWhatDescription1": "实时压力是 DoubleFeel 根据你当前的 HRV、心率状态与个人历史数据变化,动态生成的身体压力指标。",
"todayRealtimeStressWhatDescription2": "压力值越高,代表你的身体状态相比平时偏离越明显,可能正处于疲劳、恢复不足或高压力状态。",
"todayRealtimeStressWhatDescription3": "它能够帮助你更快发现身体变化,并及时调整休息、运动与生活节奏。",
"todayRealtimeStressDivisionTitle": "实时压力如何划分?",
"todayRealtimeStressDivisionIntro": "实时压力以百分比形式展示:",
"todayRealtimeStressExcellentRange": "状态优秀:1%~20%",
"todayRealtimeStressNormalRange": "状态正常:21%~60%",
"todayRealtimeStressCautionRange": "注意压力:61%~80%",
"todayRealtimeStressOverloadRange": "压力过载:81%~100%",
"todayRealtimeStressExcellentDescription": "身体恢复状态较好,整体较放松。",
"todayRealtimeStressNormalDescription": "身体处于正常波动范围。",
"todayRealtimeStressCautionDescription": "身体可能正在积累压力,需要适当休息与恢复。",
"todayRealtimeStressOverloadDescription": "身体压力明显偏高,建议减少负荷、注意睡眠与恢复。",
"todayRealtimeStressDivisionBaseline": "以上区间会结合你的个人基线动态调整,不同用户之间并不直接比较。",
"todayRealtimeStressDivisionAwake": "此外,实时压力主要反映清醒状态下的身体压力变化。",
"todayRealtimeStressLowBetterTitle": "实时压力越低越好吗?",
"todayRealtimeStressLowBetterNo": "并不一定。",
"todayRealtimeStressLowBetterType": "身体压力分为“正常压力”与“异常压力”。",
"todayRealtimeStressLowBetterExample": "例如:运动期间或运动后,实时压力短时间升高属于正常恢复反应;工作专注、情绪兴奋时,压力也可能暂时升高,这些都属于正常的身体调节。",
"todayRealtimeStressLowBetterHighStress": "但如果在静息、久坐或睡眠不足的情况下,压力长期偏高,则可能意味着身体疲劳、心理压力较大、睡眠恢复不足、运动恢复不充分、摄入过多咖啡因、酒精或刺激物、身体可能处于不适状态。",
"todayRealtimeStressLowBetterTrend": "DoubleFeel 更关注的是你的长期变化趋势,而不是单次波动。",
"todayRealtimeStressScenarioTitle": "HRV 与实时压力适用场景?",
"todayRealtimeStressScenarioHrvDefault": "在 Apple Watch 的默认设置下,HRV 每 2~5 小时更新一次。",
"todayRealtimeStressScenarioRegionLimit": "在部分地区,由于 Apple Watch 的呼吸功能受限,HRV 的更新频率可能会受到影响,并且开启呼吸功能后也会消耗更多电量。",
"todayRealtimeStressScenarioIntro": "为了解决 HRV 更新间隔较长的问题,DoubleFeel 设计了实时压力功能:",
"todayRealtimeStressScenarioUpdateEvery6Min": "· 实时压力每 6 分钟更新一次",
"todayRealtimeStressScenarioTimely": "· 可以更及时地反映身体状态变化",
"todayRealtimeStressScenarioConsistentTrend": "· 在大多数情况下,实时压力趋势与 HRV 趋势是一致的",
"todayRealtimeStressScenarioSummary": "这样用户既能获得 HRV 的长期趋势,也能通过实时压力获得短时身体状态的参考。",
"todayFaqNoDataTitle": "APP或表盘有没有数据怎么办?",
"todayFaqNoDataDescription1": "1. 确认苹果手表系统在10.0以上,手机系统在14以上,系统版本可在「关于本机」内查看。",
"todayFaqNoDataDescription2": "2. 确认是否开启所有权限:手机「健康」-「共享」-「app」-「DoubleFeel」-「打开所有权限」。",
"todayFaqNoDataDescription3": "3. 确认设备是否处于省电模式、低电量状态或手表佩戴未贴紧,以上情况会影响手表数据采集。",
"todayFaqContactPrefix": "如以上均检查无问题,可以",
"todayFaqContactAction": "联系我们",
"todayFaqContactSuffix": "。",
"todayFaqWatchNoNotificationTitle": "手表无法收到状态通知?",
"todayFaqWatchNoNotificationDescription1": "苹果手表和手机的通知展示有优先级:当手机已解锁并亮屏时,通知只会在手机端展示,不会在手表上出现。",
"todayFaqWatchNoNotificationDescription2": "若压力数据可正常显示和自动更新,但手表未收到通知,可尝试以下操作:",
"todayFaqWatchNoNotificationCheckPhoneNotification": "1. 检查手机是否打开通知(设置-DoubleFeel-通知)。",
"todayFaqWatchNoNotificationCheckPhoneBackgroundRefresh": "2. 检查手机是否打开后台App刷新(设置-DoubleFeel-后台App刷新)。",
"todayFaqWatchNoNotificationCheckWatchBackgroundRefresh": "3. 检查手表是否打开后台App刷新(设置-通用-后台App刷新,并确保DoubleFeel开启)。",
"todayFaqWatchNoNotificationCheckModes": "4. 确保未处于低电量/专注/勿扰/剧院/睡眠等模式。",
"todayFaqWatchNoNotificationReinstall": "5. 重装DoubleFeel 并重启AppleWatch与iPhone。",
"todayFaqWatchFaceDelayTitle": "手表表盘数据不更新或有延迟?",
"todayFaqWatchFaceDelayDescription1": "由于苹果系统限制,所有手表表盘(第三方或官方)都会存在几分钟至半小时的延迟,开发者无法控制刷新频率。",
"todayFaqWatchFaceDelayIfOverOneHour": "若手机数据刷新后超过1小时表盘仍未更新:",
"todayFaqWatchFaceDelayOpenWatchApp": "请在手表上手动打开DoubleFeel,等待约1分钟。",
"todayFaqWatchFaceDelayIfStill": "若仍未更新:",
"todayFaqWatchFaceDelayRestartApp": "关闭DoubleFeel后台进程并重启。",
"todayFaqWatchFaceDelayCheckIntro": "仍无效时,请检查:",
"todayFaqWatchFaceDelayCheckData": "· 手机和手表app是否可正常看到HRV数据。",
"todayFaqWatchFaceDelayCheckPhoneHealth": "· 确保手机端「iOS设置-隐私与安全性-健康-DoubleFeel」全部授权。",
"todayFaqWatchFaceDelayCheckWatchHealth": "· 确保手表端「设置-健康-数据来源、App和服务-DoubleFeel」全部授权。",
"todayFaqWatchFaceDelayCheckBackgroundRefresh": "· 确认AppleWatch-设置-通用-后台App刷新中DoubleFeel已开启。",
"todayFaqWatchFaceDelayRestartWatch": "· 若仍未自动刷新,请重启手表。长时间运行或后台占用过高可能导致表盘暂停更新。",
"todayFaqWatchFaceBlackScreenTitle": "手表表盘出现黑屏?",
"todayFaqWatchFaceBlackScreenDescription": "若添加专属互动表盘后出现黑屏(仅显示时间和日期),可长按表盘,点击「编辑」,左滑至「复杂功能」,选择 DoubleFeel,然后按需选择各组件重新添加。"
}
... ...
... ... @@ -758,6 +758,696 @@ abstract class AppLocalizations {
/// In zh, this message translates to:
/// **'授权访问健康数据'**
String get todayHealthDataAuthAction;
/// No description provided for @measureYourHrvNow.
///
/// In zh, this message translates to:
/// **'立即测量HRV'**
String get measureYourHrvNow;
/// No description provided for @todayBottomSheetGotIt.
///
/// In zh, this message translates to:
/// **'我知道了'**
String get todayBottomSheetGotIt;
/// No description provided for @todayFaqTitle.
///
/// In zh, this message translates to:
/// **'常见问题'**
String get todayFaqTitle;
/// No description provided for @todayFaqSectionTitle.
///
/// In zh, this message translates to:
/// **'DoubleFeel 常见问题'**
String get todayFaqSectionTitle;
/// No description provided for @todayFaqLinkNoData.
///
/// In zh, this message translates to:
/// **'APP或表盘有没有数据怎么办?'**
String get todayFaqLinkNoData;
/// No description provided for @todayFaqLinkHrvRealtimeUpdate.
///
/// In zh, this message translates to:
/// **'HRV数据如何实时更新?'**
String get todayFaqLinkHrvRealtimeUpdate;
/// No description provided for @todayFaqLinkWatchNoStatusNotification.
///
/// In zh, this message translates to:
/// **'手表为什么无法收到状态通知?'**
String get todayFaqLinkWatchNoStatusNotification;
/// No description provided for @todayFaqLinkWatchNoStatusAndInteractionNotification.
///
/// In zh, this message translates to:
/// **'手表为什么无法收到状态和互动通知?'**
String get todayFaqLinkWatchNoStatusAndInteractionNotification;
/// No description provided for @todayFaqLinkWatchFaceDataDelay.
///
/// In zh, this message translates to:
/// **'手表表盘数据不更新或者有延迟?'**
String get todayFaqLinkWatchFaceDataDelay;
/// No description provided for @todayFaqLinkWatchFaceBlackScreen.
///
/// In zh, this message translates to:
/// **'手表表盘为什么会出现黑屏?'**
String get todayFaqLinkWatchFaceBlackScreen;
/// No description provided for @todayStressStatusTitle.
///
/// In zh, this message translates to:
/// **'综合压力状态说明'**
String get todayStressStatusTitle;
/// No description provided for @todayHrvPrincipleTitle.
///
/// In zh, this message translates to:
/// **'HRV测量原理'**
String get todayHrvPrincipleTitle;
/// No description provided for @todayRealtimeStressTitle.
///
/// In zh, this message translates to:
/// **'实时压力原理'**
String get todayRealtimeStressTitle;
/// No description provided for @todayStressStatusOverload.
///
/// In zh, this message translates to:
/// **'压力过载'**
String get todayStressStatusOverload;
/// No description provided for @todayStressStatusCaution.
///
/// In zh, this message translates to:
/// **'注意压力'**
String get todayStressStatusCaution;
/// No description provided for @todayStressStatusNormal.
///
/// In zh, this message translates to:
/// **'状态正常'**
String get todayStressStatusNormal;
/// No description provided for @todayStressStatusExcellent.
///
/// In zh, this message translates to:
/// **'状态优秀'**
String get todayStressStatusExcellent;
/// No description provided for @todayStressStatusInsufficientData.
///
/// In zh, this message translates to:
/// **'数据不足'**
String get todayStressStatusInsufficientData;
/// No description provided for @todayStressStatusOverloadDescription.
///
/// In zh, this message translates to:
/// **'当前 HRV 明显低于你的长期平均水平,可能意味着身体疲劳、压力过高或恢复不足。建议及时休息。'**
String get todayStressStatusOverloadDescription;
/// No description provided for @todayStressStatusCautionDescription.
///
/// In zh, this message translates to:
/// **'当前 HRV 低于正常范围,身体可能正在积累压力,需要注意作息与恢复。'**
String get todayStressStatusCautionDescription;
/// No description provided for @todayStressStatusNormalDescription.
///
/// In zh, this message translates to:
/// **'当前身体状态处于你的正常波动范围内。'**
String get todayStressStatusNormalDescription;
/// No description provided for @todayStressStatusExcellentDescription.
///
/// In zh, this message translates to:
/// **'当前 HRV 高于近期平均水平,代表身体恢复与整体状态较好。'**
String get todayStressStatusExcellentDescription;
/// No description provided for @todayStressStatusInsufficientDataDescription.
///
/// In zh, this message translates to:
/// **'当前可用数据不足,暂时无法准确判断压力状态。'**
String get todayStressStatusInsufficientDataDescription;
/// No description provided for @todayHrvMeasurementIntro.
///
/// In zh, this message translates to:
/// **'AppleWatch默认每2-5小时测量一次HRV,如果你希望立即手动进行测量,可以参考以下方法:'**
String get todayHrvMeasurementIntro;
/// No description provided for @todayHrvMeasurementStep1.
///
/// In zh, this message translates to:
/// **'1、戴紧AppleWatch,坐下来,保持心境平和'**
String get todayHrvMeasurementStep1;
/// No description provided for @todayHrvMeasurementStep2.
///
/// In zh, this message translates to:
/// **'2、打开AppleWatch上的「正念」里的「呼吸」'**
String get todayHrvMeasurementStep2;
/// No description provided for @todayHrvMeasurementStep3.
///
/// In zh, this message translates to:
/// **'3、保持平稳的呼吸,等待1-3分钟'**
String get todayHrvMeasurementStep3;
/// No description provided for @todayHrvMeasurementStep4.
///
/// In zh, this message translates to:
/// **'4、完成呼吸后,锁屏一次再解锁你的iPhone'**
String get todayHrvMeasurementStep4;
/// No description provided for @todayHrvMeasurementStep5.
///
/// In zh, this message translates to:
/// **'5、等待一分钟左右,StressWatch会收到你的数据并展示'**
String get todayHrvMeasurementStep5;
/// No description provided for @todayHrvMeasurementHint.
///
/// In zh, this message translates to:
/// **'提示:数据源来自AppleWatch,在测量之后可能存在延迟或是数据未能同步的情况。如若出现上述情况,请重新测量并等待数据读取。'**
String get todayHrvMeasurementHint;
/// No description provided for @todayHrvMeasurementWarning.
///
/// In zh, this message translates to:
/// **'注意:需打开健康里的权限,同时关闭省电模式。'**
String get todayHrvMeasurementWarning;
/// No description provided for @todayStressStatusWhatTitle.
///
/// In zh, this message translates to:
/// **'什么是综合压力状态?'**
String get todayStressStatusWhatTitle;
/// No description provided for @todayStressStatusWhatDescription1.
///
/// In zh, this message translates to:
/// **'DoubleFeel 会结合你过去 30 天的 HRV(心率变异性)、静息心率以及当天的身体状态变化,综合评估你的整体压力水平。'**
String get todayStressStatusWhatDescription1;
/// No description provided for @todayStressStatusWhatDescription2.
///
/// In zh, this message translates to:
/// **'由于 HRV 会随着情绪、运动、睡眠和疲劳不断波动,单次数据参考意义有限,因此我们更建议关注一整天的综合压力状态,让结果更稳定、更有参考价值。综合压力不仅能帮助你了解自己的身体状态,也能让亲密联系人更及时地关注你的变化。'**
String get todayStressStatusWhatDescription2;
/// No description provided for @todayStressStatusWhyHrvTitle.
///
/// In zh, this message translates to:
/// **'为什么要参考 HRV(心率变异性)?'**
String get todayStressStatusWhyHrvTitle;
/// No description provided for @todayStressStatusWhyHrvDescription.
///
/// In zh, this message translates to:
/// **'HRV 是衡量身体压力与恢复能力的重要指标。'**
String get todayStressStatusWhyHrvDescription;
/// No description provided for @todayStressStatusUsually.
///
/// In zh, this message translates to:
/// **'通常来说:'**
String get todayStressStatusUsually;
/// No description provided for @todayStressStatusHrvHigher.
///
/// In zh, this message translates to:
/// **'· HRV 越高,代表身体恢复状态越好'**
String get todayStressStatusHrvHigher;
/// No description provided for @todayStressStatusHrvLower.
///
/// In zh, this message translates to:
/// **'· HRV 越低,可能意味着疲劳、压力或睡眠不足'**
String get todayStressStatusHrvLower;
/// No description provided for @todayStressStatusHrvChangesFast.
///
/// In zh, this message translates to:
/// **'· HRV 变化较快,更适合观察短时间内的身体状态变化。'**
String get todayStressStatusHrvChangesFast;
/// No description provided for @todayStressStatusAppWatchDifferenceTitle.
///
/// In zh, this message translates to:
/// **'手机 App 与 Apple Watch 显示的压力状态有什么区别?'**
String get todayStressStatusAppWatchDifferenceTitle;
/// No description provided for @todayStressStatusAppWatchDifferenceApp.
///
/// In zh, this message translates to:
/// **'手机 App 首页显示的是当天的综合压力状态,会综合分析 HRV、静息心率与整体趋势。'**
String get todayStressStatusAppWatchDifferenceApp;
/// No description provided for @todayStressStatusAppWatchDifferenceWatch.
///
/// In zh, this message translates to:
/// **'Apple Watch 显示的是最近一次的实时压力状态,更适合快速查看当前身体变化。'**
String get todayStressStatusAppWatchDifferenceWatch;
/// No description provided for @todayStressStatusWaitingDataTitle.
///
/// In zh, this message translates to:
/// **'为什么会出现“等待数据”?'**
String get todayStressStatusWaitingDataTitle;
/// No description provided for @todayStressStatusWaitingDataDescription1.
///
/// In zh, this message translates to:
/// **'“等待数据”代表当前采集到的数据量不足,暂时无法生成可靠的压力评估。'**
String get todayStressStatusWaitingDataDescription1;
/// No description provided for @todayStressStatusWaitingDataDescription2.
///
/// In zh, this message translates to:
/// **'请继续佩戴 Apple Watch,等待系统自动采集数据。'**
String get todayStressStatusWaitingDataDescription2;
/// No description provided for @todayStressStatusWaitingDataReasonsIntro.
///
/// In zh, this message translates to:
/// **'可能原因包括:'**
String get todayStressStatusWaitingDataReasonsIntro;
/// No description provided for @todayStressStatusWaitingDataReason1.
///
/// In zh, this message translates to:
/// **'1. HRV 数据采样不足'**
String get todayStressStatusWaitingDataReason1;
/// No description provided for @todayStressStatusWaitingDataReason2.
///
/// In zh, this message translates to:
/// **'2. 缺少静息心率数据'**
String get todayStressStatusWaitingDataReason2;
/// No description provided for @todayStressStatusWaitingDataReason3.
///
/// In zh, this message translates to:
/// **'3. Apple Watch 佩戴时间较短'**
String get todayStressStatusWaitingDataReason3;
/// No description provided for @todayStressStatusWaitingDataReason4.
///
/// In zh, this message translates to:
/// **'4. Apple Health 权限未开启'**
String get todayStressStatusWaitingDataReason4;
/// No description provided for @todayHrvPrincipleHowMeasureTitle.
///
/// In zh, this message translates to:
/// **'DoubleFeel 如何测量压力状态?'**
String get todayHrvPrincipleHowMeasureTitle;
/// No description provided for @todayHrvPrincipleHowMeasureDescription1.
///
/// In zh, this message translates to:
/// **'当你正常佩戴 Apple Watch 时,系统会自动采集你的心率数据,并同步至 Apple Health。'**
String get todayHrvPrincipleHowMeasureDescription1;
/// No description provided for @todayHrvPrincipleHowMeasureDescription2.
///
/// In zh, this message translates to:
/// **'DoubleFeel 会基于这些数据计算 HRV(心率变异性)相关指标,用于评估你的身体压力与恢复状态。'**
String get todayHrvPrincipleHowMeasureDescription2;
/// No description provided for @todayHrvPrincipleHowMeasureDescription3.
///
/// In zh, this message translates to:
/// **'HRV 对压力、疲劳、睡眠、情绪与身体恢复都非常敏感,因此它能够帮助我们更早发现身体状态变化。'**
String get todayHrvPrincipleHowMeasureDescription3;
/// No description provided for @todayHrvPrincipleHowMeasureDescription4.
///
/// In zh, this message translates to:
/// **'为了让结果更准确,DoubleFeel 会将你当前的 HRV 状态与过去 30 天的个人平均水平进行对比,而不是直接与其他人比较。'**
String get todayHrvPrincipleHowMeasureDescription4;
/// No description provided for @todayRealtimeStressWhatTitle.
///
/// In zh, this message translates to:
/// **'什么是实时压力?'**
String get todayRealtimeStressWhatTitle;
/// No description provided for @todayRealtimeStressWhatDescription1.
///
/// In zh, this message translates to:
/// **'实时压力是 DoubleFeel 根据你当前的 HRV、心率状态与个人历史数据变化,动态生成的身体压力指标。'**
String get todayRealtimeStressWhatDescription1;
/// No description provided for @todayRealtimeStressWhatDescription2.
///
/// In zh, this message translates to:
/// **'压力值越高,代表你的身体状态相比平时偏离越明显,可能正处于疲劳、恢复不足或高压力状态。'**
String get todayRealtimeStressWhatDescription2;
/// No description provided for @todayRealtimeStressWhatDescription3.
///
/// In zh, this message translates to:
/// **'它能够帮助你更快发现身体变化,并及时调整休息、运动与生活节奏。'**
String get todayRealtimeStressWhatDescription3;
/// No description provided for @todayRealtimeStressDivisionTitle.
///
/// In zh, this message translates to:
/// **'实时压力如何划分?'**
String get todayRealtimeStressDivisionTitle;
/// No description provided for @todayRealtimeStressDivisionIntro.
///
/// In zh, this message translates to:
/// **'实时压力以百分比形式展示:'**
String get todayRealtimeStressDivisionIntro;
/// No description provided for @todayRealtimeStressExcellentRange.
///
/// In zh, this message translates to:
/// **'状态优秀:1%~20%'**
String get todayRealtimeStressExcellentRange;
/// No description provided for @todayRealtimeStressNormalRange.
///
/// In zh, this message translates to:
/// **'状态正常:21%~60%'**
String get todayRealtimeStressNormalRange;
/// No description provided for @todayRealtimeStressCautionRange.
///
/// In zh, this message translates to:
/// **'注意压力:61%~80%'**
String get todayRealtimeStressCautionRange;
/// No description provided for @todayRealtimeStressOverloadRange.
///
/// In zh, this message translates to:
/// **'压力过载:81%~100%'**
String get todayRealtimeStressOverloadRange;
/// No description provided for @todayRealtimeStressExcellentDescription.
///
/// In zh, this message translates to:
/// **'身体恢复状态较好,整体较放松。'**
String get todayRealtimeStressExcellentDescription;
/// No description provided for @todayRealtimeStressNormalDescription.
///
/// In zh, this message translates to:
/// **'身体处于正常波动范围。'**
String get todayRealtimeStressNormalDescription;
/// No description provided for @todayRealtimeStressCautionDescription.
///
/// In zh, this message translates to:
/// **'身体可能正在积累压力,需要适当休息与恢复。'**
String get todayRealtimeStressCautionDescription;
/// No description provided for @todayRealtimeStressOverloadDescription.
///
/// In zh, this message translates to:
/// **'身体压力明显偏高,建议减少负荷、注意睡眠与恢复。'**
String get todayRealtimeStressOverloadDescription;
/// No description provided for @todayRealtimeStressDivisionBaseline.
///
/// In zh, this message translates to:
/// **'以上区间会结合你的个人基线动态调整,不同用户之间并不直接比较。'**
String get todayRealtimeStressDivisionBaseline;
/// No description provided for @todayRealtimeStressDivisionAwake.
///
/// In zh, this message translates to:
/// **'此外,实时压力主要反映清醒状态下的身体压力变化。'**
String get todayRealtimeStressDivisionAwake;
/// No description provided for @todayRealtimeStressLowBetterTitle.
///
/// In zh, this message translates to:
/// **'实时压力越低越好吗?'**
String get todayRealtimeStressLowBetterTitle;
/// No description provided for @todayRealtimeStressLowBetterNo.
///
/// In zh, this message translates to:
/// **'并不一定。'**
String get todayRealtimeStressLowBetterNo;
/// No description provided for @todayRealtimeStressLowBetterType.
///
/// In zh, this message translates to:
/// **'身体压力分为“正常压力”与“异常压力”。'**
String get todayRealtimeStressLowBetterType;
/// No description provided for @todayRealtimeStressLowBetterExample.
///
/// In zh, this message translates to:
/// **'例如:运动期间或运动后,实时压力短时间升高属于正常恢复反应;工作专注、情绪兴奋时,压力也可能暂时升高,这些都属于正常的身体调节。'**
String get todayRealtimeStressLowBetterExample;
/// No description provided for @todayRealtimeStressLowBetterHighStress.
///
/// In zh, this message translates to:
/// **'但如果在静息、久坐或睡眠不足的情况下,压力长期偏高,则可能意味着身体疲劳、心理压力较大、睡眠恢复不足、运动恢复不充分、摄入过多咖啡因、酒精或刺激物、身体可能处于不适状态。'**
String get todayRealtimeStressLowBetterHighStress;
/// No description provided for @todayRealtimeStressLowBetterTrend.
///
/// In zh, this message translates to:
/// **'DoubleFeel 更关注的是你的长期变化趋势,而不是单次波动。'**
String get todayRealtimeStressLowBetterTrend;
/// No description provided for @todayRealtimeStressScenarioTitle.
///
/// In zh, this message translates to:
/// **'HRV 与实时压力适用场景?'**
String get todayRealtimeStressScenarioTitle;
/// No description provided for @todayRealtimeStressScenarioHrvDefault.
///
/// In zh, this message translates to:
/// **'在 Apple Watch 的默认设置下,HRV 每 2~5 小时更新一次。'**
String get todayRealtimeStressScenarioHrvDefault;
/// No description provided for @todayRealtimeStressScenarioRegionLimit.
///
/// In zh, this message translates to:
/// **'在部分地区,由于 Apple Watch 的呼吸功能受限,HRV 的更新频率可能会受到影响,并且开启呼吸功能后也会消耗更多电量。'**
String get todayRealtimeStressScenarioRegionLimit;
/// No description provided for @todayRealtimeStressScenarioIntro.
///
/// In zh, this message translates to:
/// **'为了解决 HRV 更新间隔较长的问题,DoubleFeel 设计了实时压力功能:'**
String get todayRealtimeStressScenarioIntro;
/// No description provided for @todayRealtimeStressScenarioUpdateEvery6Min.
///
/// In zh, this message translates to:
/// **'· 实时压力每 6 分钟更新一次'**
String get todayRealtimeStressScenarioUpdateEvery6Min;
/// No description provided for @todayRealtimeStressScenarioTimely.
///
/// In zh, this message translates to:
/// **'· 可以更及时地反映身体状态变化'**
String get todayRealtimeStressScenarioTimely;
/// No description provided for @todayRealtimeStressScenarioConsistentTrend.
///
/// In zh, this message translates to:
/// **'· 在大多数情况下,实时压力趋势与 HRV 趋势是一致的'**
String get todayRealtimeStressScenarioConsistentTrend;
/// No description provided for @todayRealtimeStressScenarioSummary.
///
/// In zh, this message translates to:
/// **'这样用户既能获得 HRV 的长期趋势,也能通过实时压力获得短时身体状态的参考。'**
String get todayRealtimeStressScenarioSummary;
/// No description provided for @todayFaqNoDataTitle.
///
/// In zh, this message translates to:
/// **'APP或表盘有没有数据怎么办?'**
String get todayFaqNoDataTitle;
/// No description provided for @todayFaqNoDataDescription1.
///
/// In zh, this message translates to:
/// **'1. 确认苹果手表系统在10.0以上,手机系统在14以上,系统版本可在「关于本机」内查看。'**
String get todayFaqNoDataDescription1;
/// No description provided for @todayFaqNoDataDescription2.
///
/// In zh, this message translates to:
/// **'2. 确认是否开启所有权限:手机「健康」-「共享」-「app」-「DoubleFeel」-「打开所有权限」。'**
String get todayFaqNoDataDescription2;
/// No description provided for @todayFaqNoDataDescription3.
///
/// In zh, this message translates to:
/// **'3. 确认设备是否处于省电模式、低电量状态或手表佩戴未贴紧,以上情况会影响手表数据采集。'**
String get todayFaqNoDataDescription3;
/// No description provided for @todayFaqContactPrefix.
///
/// In zh, this message translates to:
/// **'如以上均检查无问题,可以'**
String get todayFaqContactPrefix;
/// No description provided for @todayFaqContactAction.
///
/// In zh, this message translates to:
/// **'联系我们'**
String get todayFaqContactAction;
/// No description provided for @todayFaqContactSuffix.
///
/// In zh, this message translates to:
/// **'。'**
String get todayFaqContactSuffix;
/// No description provided for @todayFaqWatchNoNotificationTitle.
///
/// In zh, this message translates to:
/// **'手表无法收到状态通知?'**
String get todayFaqWatchNoNotificationTitle;
/// No description provided for @todayFaqWatchNoNotificationDescription1.
///
/// In zh, this message translates to:
/// **'苹果手表和手机的通知展示有优先级:当手机已解锁并亮屏时,通知只会在手机端展示,不会在手表上出现。'**
String get todayFaqWatchNoNotificationDescription1;
/// No description provided for @todayFaqWatchNoNotificationDescription2.
///
/// In zh, this message translates to:
/// **'若压力数据可正常显示和自动更新,但手表未收到通知,可尝试以下操作:'**
String get todayFaqWatchNoNotificationDescription2;
/// No description provided for @todayFaqWatchNoNotificationCheckPhoneNotification.
///
/// In zh, this message translates to:
/// **'1. 检查手机是否打开通知(设置-DoubleFeel-通知)。'**
String get todayFaqWatchNoNotificationCheckPhoneNotification;
/// No description provided for @todayFaqWatchNoNotificationCheckPhoneBackgroundRefresh.
///
/// In zh, this message translates to:
/// **'2. 检查手机是否打开后台App刷新(设置-DoubleFeel-后台App刷新)。'**
String get todayFaqWatchNoNotificationCheckPhoneBackgroundRefresh;
/// No description provided for @todayFaqWatchNoNotificationCheckWatchBackgroundRefresh.
///
/// In zh, this message translates to:
/// **'3. 检查手表是否打开后台App刷新(设置-通用-后台App刷新,并确保DoubleFeel开启)。'**
String get todayFaqWatchNoNotificationCheckWatchBackgroundRefresh;
/// No description provided for @todayFaqWatchNoNotificationCheckModes.
///
/// In zh, this message translates to:
/// **'4. 确保未处于低电量/专注/勿扰/剧院/睡眠等模式。'**
String get todayFaqWatchNoNotificationCheckModes;
/// No description provided for @todayFaqWatchNoNotificationReinstall.
///
/// In zh, this message translates to:
/// **'5. 重装DoubleFeel 并重启AppleWatch与iPhone。'**
String get todayFaqWatchNoNotificationReinstall;
/// No description provided for @todayFaqWatchFaceDelayTitle.
///
/// In zh, this message translates to:
/// **'手表表盘数据不更新或有延迟?'**
String get todayFaqWatchFaceDelayTitle;
/// No description provided for @todayFaqWatchFaceDelayDescription1.
///
/// In zh, this message translates to:
/// **'由于苹果系统限制,所有手表表盘(第三方或官方)都会存在几分钟至半小时的延迟,开发者无法控制刷新频率。'**
String get todayFaqWatchFaceDelayDescription1;
/// No description provided for @todayFaqWatchFaceDelayIfOverOneHour.
///
/// In zh, this message translates to:
/// **'若手机数据刷新后超过1小时表盘仍未更新:'**
String get todayFaqWatchFaceDelayIfOverOneHour;
/// No description provided for @todayFaqWatchFaceDelayOpenWatchApp.
///
/// In zh, this message translates to:
/// **'请在手表上手动打开DoubleFeel,等待约1分钟。'**
String get todayFaqWatchFaceDelayOpenWatchApp;
/// No description provided for @todayFaqWatchFaceDelayIfStill.
///
/// In zh, this message translates to:
/// **'若仍未更新:'**
String get todayFaqWatchFaceDelayIfStill;
/// No description provided for @todayFaqWatchFaceDelayRestartApp.
///
/// In zh, this message translates to:
/// **'关闭DoubleFeel后台进程并重启。'**
String get todayFaqWatchFaceDelayRestartApp;
/// No description provided for @todayFaqWatchFaceDelayCheckIntro.
///
/// In zh, this message translates to:
/// **'仍无效时,请检查:'**
String get todayFaqWatchFaceDelayCheckIntro;
/// No description provided for @todayFaqWatchFaceDelayCheckData.
///
/// In zh, this message translates to:
/// **'· 手机和手表app是否可正常看到HRV数据。'**
String get todayFaqWatchFaceDelayCheckData;
/// No description provided for @todayFaqWatchFaceDelayCheckPhoneHealth.
///
/// In zh, this message translates to:
/// **'· 确保手机端「iOS设置-隐私与安全性-健康-DoubleFeel」全部授权。'**
String get todayFaqWatchFaceDelayCheckPhoneHealth;
/// No description provided for @todayFaqWatchFaceDelayCheckWatchHealth.
///
/// In zh, this message translates to:
/// **'· 确保手表端「设置-健康-数据来源、App和服务-DoubleFeel」全部授权。'**
String get todayFaqWatchFaceDelayCheckWatchHealth;
/// No description provided for @todayFaqWatchFaceDelayCheckBackgroundRefresh.
///
/// In zh, this message translates to:
/// **'· 确认AppleWatch-设置-通用-后台App刷新中DoubleFeel已开启。'**
String get todayFaqWatchFaceDelayCheckBackgroundRefresh;
/// No description provided for @todayFaqWatchFaceDelayRestartWatch.
///
/// In zh, this message translates to:
/// **'· 若仍未自动刷新,请重启手表。长时间运行或后台占用过高可能导致表盘暂停更新。'**
String get todayFaqWatchFaceDelayRestartWatch;
/// No description provided for @todayFaqWatchFaceBlackScreenTitle.
///
/// In zh, this message translates to:
/// **'手表表盘出现黑屏?'**
String get todayFaqWatchFaceBlackScreenTitle;
/// No description provided for @todayFaqWatchFaceBlackScreenDescription.
///
/// In zh, this message translates to:
/// **'若添加专属互动表盘后出现黑屏(仅显示时间和日期),可长按表盘,点击「编辑」,左滑至「复杂功能」,选择 DoubleFeel,然后按需选择各组件重新添加。'**
String get todayFaqWatchFaceBlackScreenDescription;
}
class _AppLocalizationsDelegate
... ...
... ... @@ -364,4 +364,438 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get todayHealthDataAuthAction => 'Authorize health data access';
@override
String get measureYourHrvNow => 'Measure your HRV now';
@override
String get todayBottomSheetGotIt => 'Got it';
@override
String get todayFaqTitle => 'FAQ';
@override
String get todayFaqSectionTitle => 'DoubleFeel FAQ';
@override
String get todayFaqLinkNoData => 'What if the app or watch face has no data?';
@override
String get todayFaqLinkHrvRealtimeUpdate =>
'How can HRV data update in real time?';
@override
String get todayFaqLinkWatchNoStatusNotification =>
'Why can\'t my watch receive status notifications?';
@override
String get todayFaqLinkWatchNoStatusAndInteractionNotification =>
'Why can\'t my watch receive status and interaction notifications?';
@override
String get todayFaqLinkWatchFaceDataDelay =>
'Why is watch face data delayed or not updating?';
@override
String get todayFaqLinkWatchFaceBlackScreen =>
'Why does the watch face turn black?';
@override
String get todayStressStatusTitle => 'Overall stress status';
@override
String get todayHrvPrincipleTitle => 'How HRV is measured';
@override
String get todayRealtimeStressTitle => 'How real-time stress works';
@override
String get todayStressStatusOverload => 'Stress overload';
@override
String get todayStressStatusCaution => 'Stress warning';
@override
String get todayStressStatusNormal => 'Normal';
@override
String get todayStressStatusExcellent => 'Excellent';
@override
String get todayStressStatusInsufficientData => 'Insufficient data';
@override
String get todayStressStatusOverloadDescription =>
'Your current HRV is much lower than your long-term average, which may indicate fatigue, high stress, or insufficient recovery. Rest is recommended.';
@override
String get todayStressStatusCautionDescription =>
'Your current HRV is below the normal range, and your body may be accumulating stress. Pay attention to rest and recovery.';
@override
String get todayStressStatusNormalDescription =>
'Your current body state is within your normal fluctuation range.';
@override
String get todayStressStatusExcellentDescription =>
'Your current HRV is higher than your recent average, indicating better recovery and overall state.';
@override
String get todayStressStatusInsufficientDataDescription =>
'There is not enough available data to accurately assess your stress state yet.';
@override
String get todayHrvMeasurementIntro =>
'Apple Watch measures HRV every 2-5 hours by default. If you want to measure it manually right now, follow these steps:';
@override
String get todayHrvMeasurementStep1 =>
'1. Wear your Apple Watch snugly, sit down, and stay calm';
@override
String get todayHrvMeasurementStep2 =>
'2. Open Mindfulness on Apple Watch and start Breathe';
@override
String get todayHrvMeasurementStep3 =>
'3. Keep breathing steadily and wait 1-3 minutes';
@override
String get todayHrvMeasurementStep4 =>
'4. After breathing is complete, lock and unlock your iPhone once';
@override
String get todayHrvMeasurementStep5 =>
'5. Wait about one minute. StressWatch will receive and display your data';
@override
String get todayHrvMeasurementHint =>
'Tip: Data comes from Apple Watch. After measurement, there may be delays or data may not sync immediately. If this happens, measure again and wait for the data to be read.';
@override
String get todayHrvMeasurementWarning =>
'Note: Health permissions must be enabled, and Low Power Mode must be turned off.';
@override
String get todayStressStatusWhatTitle => 'What is overall stress status?';
@override
String get todayStressStatusWhatDescription1 =>
'DoubleFeel combines your HRV (heart rate variability), resting heart rate, and body-state changes from the past 30 days to assess your overall stress level.';
@override
String get todayStressStatusWhatDescription2 =>
'Because HRV fluctuates with emotions, exercise, sleep, and fatigue, a single reading has limited value. We recommend focusing on your overall stress status across the day, which is more stable and useful. It helps you understand your body state and helps close contacts notice changes in time.';
@override
String get todayStressStatusWhyHrvTitle =>
'Why use HRV (heart rate variability)?';
@override
String get todayStressStatusWhyHrvDescription =>
'HRV is an important metric for measuring body stress and recovery capacity.';
@override
String get todayStressStatusUsually => 'In general:';
@override
String get todayStressStatusHrvHigher =>
'· Higher HRV usually means better recovery';
@override
String get todayStressStatusHrvLower =>
'· Lower HRV may indicate fatigue, stress, or insufficient sleep';
@override
String get todayStressStatusHrvChangesFast =>
'· HRV changes quickly, making it useful for short-term body-state changes.';
@override
String get todayStressStatusAppWatchDifferenceTitle =>
'How are stress statuses on the phone app and Apple Watch different?';
@override
String get todayStressStatusAppWatchDifferenceApp =>
'The phone app home page shows the day\'s overall stress status, combining HRV, resting heart rate, and overall trends.';
@override
String get todayStressStatusAppWatchDifferenceWatch =>
'Apple Watch shows the most recent real-time stress status, which is better for quickly checking your current body changes.';
@override
String get todayStressStatusWaitingDataTitle =>
'Why does Waiting for data appear?';
@override
String get todayStressStatusWaitingDataDescription1 =>
'Waiting for data means the current amount of collected data is not enough to generate a reliable stress assessment.';
@override
String get todayStressStatusWaitingDataDescription2 =>
'Please keep wearing your Apple Watch and wait for the system to collect data automatically.';
@override
String get todayStressStatusWaitingDataReasonsIntro =>
'Possible reasons include:';
@override
String get todayStressStatusWaitingDataReason1 => '1. Not enough HRV samples';
@override
String get todayStressStatusWaitingDataReason2 =>
'2. Missing resting heart rate data';
@override
String get todayStressStatusWaitingDataReason3 =>
'3. Apple Watch has not been worn long enough';
@override
String get todayStressStatusWaitingDataReason4 =>
'4. Apple Health permissions are not enabled';
@override
String get todayHrvPrincipleHowMeasureTitle =>
'How does DoubleFeel measure stress status?';
@override
String get todayHrvPrincipleHowMeasureDescription1 =>
'When you wear Apple Watch normally, the system automatically collects your heart rate data and syncs it to Apple Health.';
@override
String get todayHrvPrincipleHowMeasureDescription2 =>
'DoubleFeel calculates HRV (heart rate variability) indicators based on this data to assess your body stress and recovery state.';
@override
String get todayHrvPrincipleHowMeasureDescription3 =>
'HRV is sensitive to stress, fatigue, sleep, emotions, and recovery, so it helps us notice body-state changes earlier.';
@override
String get todayHrvPrincipleHowMeasureDescription4 =>
'To make results more accurate, DoubleFeel compares your current HRV state with your own 30-day average instead of comparing it directly with other people.';
@override
String get todayRealtimeStressWhatTitle => 'What is real-time stress?';
@override
String get todayRealtimeStressWhatDescription1 =>
'Real-time stress is a body stress indicator dynamically generated by DoubleFeel based on your current HRV, heart rate state, and changes in your personal history.';
@override
String get todayRealtimeStressWhatDescription2 =>
'A higher stress value means your body state is deviating more from your usual baseline and may reflect fatigue, insufficient recovery, or high stress.';
@override
String get todayRealtimeStressWhatDescription3 =>
'It helps you notice body changes faster and adjust rest, exercise, and daily rhythm in time.';
@override
String get todayRealtimeStressDivisionTitle =>
'How is real-time stress divided?';
@override
String get todayRealtimeStressDivisionIntro =>
'Real-time stress is shown as a percentage:';
@override
String get todayRealtimeStressExcellentRange => 'Excellent: 1%-20%';
@override
String get todayRealtimeStressNormalRange => 'Normal: 21%-60%';
@override
String get todayRealtimeStressCautionRange => 'Stress warning: 61%-80%';
@override
String get todayRealtimeStressOverloadRange => 'Stress overload: 81%-100%';
@override
String get todayRealtimeStressExcellentDescription =>
'Your recovery state is good and you are generally relaxed.';
@override
String get todayRealtimeStressNormalDescription =>
'Your body is within the normal fluctuation range.';
@override
String get todayRealtimeStressCautionDescription =>
'Your body may be accumulating stress and needs proper rest and recovery.';
@override
String get todayRealtimeStressOverloadDescription =>
'Your body stress is clearly high. Reduce load and pay attention to sleep and recovery.';
@override
String get todayRealtimeStressDivisionBaseline =>
'These ranges are adjusted dynamically based on your personal baseline and should not be directly compared between users.';
@override
String get todayRealtimeStressDivisionAwake =>
'Real-time stress mainly reflects body stress changes while awake.';
@override
String get todayRealtimeStressLowBetterTitle =>
'Is lower real-time stress always better?';
@override
String get todayRealtimeStressLowBetterNo => 'Not necessarily.';
@override
String get todayRealtimeStressLowBetterType =>
'Body stress can be normal or abnormal.';
@override
String get todayRealtimeStressLowBetterExample =>
'For example, real-time stress rising briefly during or after exercise is a normal recovery response. It can also rise temporarily during focused work or emotional excitement, which are normal body adjustments.';
@override
String get todayRealtimeStressLowBetterHighStress =>
'But if stress remains high while resting, sitting for a long time, or after poor sleep, it may indicate physical fatigue, mental stress, insufficient sleep recovery, incomplete exercise recovery, too much caffeine, alcohol, stimulants, or possible discomfort.';
@override
String get todayRealtimeStressLowBetterTrend =>
'DoubleFeel focuses more on your long-term trend than on a single fluctuation.';
@override
String get todayRealtimeStressScenarioTitle =>
'When should HRV and real-time stress be used?';
@override
String get todayRealtimeStressScenarioHrvDefault =>
'With Apple Watch default settings, HRV updates every 2-5 hours.';
@override
String get todayRealtimeStressScenarioRegionLimit =>
'In some regions, Apple Watch breathing features may be limited, which can affect HRV update frequency. Turning on breathing features may also consume more battery.';
@override
String get todayRealtimeStressScenarioIntro =>
'To address the long interval between HRV updates, DoubleFeel designed real-time stress:';
@override
String get todayRealtimeStressScenarioUpdateEvery6Min =>
'· Real-time stress updates every 6 minutes';
@override
String get todayRealtimeStressScenarioTimely =>
'· It can reflect body-state changes more promptly';
@override
String get todayRealtimeStressScenarioConsistentTrend =>
'· In most cases, the real-time stress trend is consistent with the HRV trend';
@override
String get todayRealtimeStressScenarioSummary =>
'This lets users see long-term HRV trends while also using real-time stress as a short-term body-state reference.';
@override
String get todayFaqNoDataTitle =>
'What if the app or watch face has no data?';
@override
String get todayFaqNoDataDescription1 =>
'1. Confirm that Apple Watch is on watchOS 10.0 or above and iPhone is on iOS 14 or above. You can check system versions in About.';
@override
String get todayFaqNoDataDescription2 =>
'2. Confirm all permissions are enabled: iPhone Health > Sharing > Apps > DoubleFeel > Turn On All Permissions.';
@override
String get todayFaqNoDataDescription3 =>
'3. Confirm the device is not in Low Power Mode, low battery, or worn too loosely, as these can affect data collection.';
@override
String get todayFaqContactPrefix =>
'If everything above is correct, you can ';
@override
String get todayFaqContactAction => 'contact us';
@override
String get todayFaqContactSuffix => '.';
@override
String get todayFaqWatchNoNotificationTitle =>
'Watch cannot receive status notifications?';
@override
String get todayFaqWatchNoNotificationDescription1 =>
'Apple Watch and iPhone notifications have priority rules: when your iPhone is unlocked and the screen is on, notifications only appear on the phone and will not appear on the watch.';
@override
String get todayFaqWatchNoNotificationDescription2 =>
'If stress data displays and updates normally but your watch does not receive notifications, try the following:';
@override
String get todayFaqWatchNoNotificationCheckPhoneNotification =>
'1. Check whether iPhone notifications are enabled (Settings > DoubleFeel > Notifications).';
@override
String get todayFaqWatchNoNotificationCheckPhoneBackgroundRefresh =>
'2. Check whether iPhone Background App Refresh is enabled (Settings > DoubleFeel > Background App Refresh).';
@override
String get todayFaqWatchNoNotificationCheckWatchBackgroundRefresh =>
'3. Check whether Apple Watch Background App Refresh is enabled (Settings > General > Background App Refresh, and make sure DoubleFeel is enabled).';
@override
String get todayFaqWatchNoNotificationCheckModes =>
'4. Make sure Low Power, Focus, Do Not Disturb, Theater, Sleep, and similar modes are off.';
@override
String get todayFaqWatchNoNotificationReinstall =>
'5. Reinstall DoubleFeel and restart Apple Watch and iPhone.';
@override
String get todayFaqWatchFaceDelayTitle =>
'Watch face data not updating or delayed?';
@override
String get todayFaqWatchFaceDelayDescription1 =>
'Due to Apple system limits, all watch faces, third-party or official, may have delays from a few minutes to half an hour. Developers cannot control the refresh frequency.';
@override
String get todayFaqWatchFaceDelayIfOverOneHour =>
'If the phone data refreshes but the watch face still has not updated after more than 1 hour:';
@override
String get todayFaqWatchFaceDelayOpenWatchApp =>
'Manually open DoubleFeel on Apple Watch and wait about 1 minute.';
@override
String get todayFaqWatchFaceDelayIfStill => 'If it still does not update:';
@override
String get todayFaqWatchFaceDelayRestartApp =>
'Close the DoubleFeel background process and restart it.';
@override
String get todayFaqWatchFaceDelayCheckIntro =>
'If it still does not work, check:';
@override
String get todayFaqWatchFaceDelayCheckData =>
'· Whether both phone and watch apps can show HRV data normally.';
@override
String get todayFaqWatchFaceDelayCheckPhoneHealth =>
'· Make sure all permissions are enabled on iPhone: iOS Settings > Privacy & Security > Health > DoubleFeel.';
@override
String get todayFaqWatchFaceDelayCheckWatchHealth =>
'· Make sure all permissions are enabled on Apple Watch: Settings > Health > Data Sources & Access > DoubleFeel.';
@override
String get todayFaqWatchFaceDelayCheckBackgroundRefresh =>
'· Confirm DoubleFeel is enabled in Apple Watch > Settings > General > Background App Refresh.';
@override
String get todayFaqWatchFaceDelayRestartWatch =>
'· If it still does not refresh automatically, restart Apple Watch. Long runtimes or high background usage may cause watch face updates to pause.';
@override
String get todayFaqWatchFaceBlackScreenTitle => 'Watch face turns black?';
@override
String get todayFaqWatchFaceBlackScreenDescription =>
'If the custom interactive watch face turns black after being added and only shows time and date, long-press the watch face, tap Edit, swipe left to Complications, choose DoubleFeel, and add each component again as needed.';
}
... ...
... ... @@ -347,4 +347,397 @@ class AppLocalizationsZh extends AppLocalizations {
@override
String get todayHealthDataAuthAction => '授权访问健康数据';
@override
String get measureYourHrvNow => '立即测量HRV';
@override
String get todayBottomSheetGotIt => '我知道了';
@override
String get todayFaqTitle => '常见问题';
@override
String get todayFaqSectionTitle => 'DoubleFeel 常见问题';
@override
String get todayFaqLinkNoData => 'APP或表盘有没有数据怎么办?';
@override
String get todayFaqLinkHrvRealtimeUpdate => 'HRV数据如何实时更新?';
@override
String get todayFaqLinkWatchNoStatusNotification => '手表为什么无法收到状态通知?';
@override
String get todayFaqLinkWatchNoStatusAndInteractionNotification =>
'手表为什么无法收到状态和互动通知?';
@override
String get todayFaqLinkWatchFaceDataDelay => '手表表盘数据不更新或者有延迟?';
@override
String get todayFaqLinkWatchFaceBlackScreen => '手表表盘为什么会出现黑屏?';
@override
String get todayStressStatusTitle => '综合压力状态说明';
@override
String get todayHrvPrincipleTitle => 'HRV测量原理';
@override
String get todayRealtimeStressTitle => '实时压力原理';
@override
String get todayStressStatusOverload => '压力过载';
@override
String get todayStressStatusCaution => '注意压力';
@override
String get todayStressStatusNormal => '状态正常';
@override
String get todayStressStatusExcellent => '状态优秀';
@override
String get todayStressStatusInsufficientData => '数据不足';
@override
String get todayStressStatusOverloadDescription =>
'当前 HRV 明显低于你的长期平均水平,可能意味着身体疲劳、压力过高或恢复不足。建议及时休息。';
@override
String get todayStressStatusCautionDescription =>
'当前 HRV 低于正常范围,身体可能正在积累压力,需要注意作息与恢复。';
@override
String get todayStressStatusNormalDescription => '当前身体状态处于你的正常波动范围内。';
@override
String get todayStressStatusExcellentDescription =>
'当前 HRV 高于近期平均水平,代表身体恢复与整体状态较好。';
@override
String get todayStressStatusInsufficientDataDescription =>
'当前可用数据不足,暂时无法准确判断压力状态。';
@override
String get todayHrvMeasurementIntro =>
'AppleWatch默认每2-5小时测量一次HRV,如果你希望立即手动进行测量,可以参考以下方法:';
@override
String get todayHrvMeasurementStep1 => '1、戴紧AppleWatch,坐下来,保持心境平和';
@override
String get todayHrvMeasurementStep2 => '2、打开AppleWatch上的「正念」里的「呼吸」';
@override
String get todayHrvMeasurementStep3 => '3、保持平稳的呼吸,等待1-3分钟';
@override
String get todayHrvMeasurementStep4 => '4、完成呼吸后,锁屏一次再解锁你的iPhone';
@override
String get todayHrvMeasurementStep5 => '5、等待一分钟左右,StressWatch会收到你的数据并展示';
@override
String get todayHrvMeasurementHint =>
'提示:数据源来自AppleWatch,在测量之后可能存在延迟或是数据未能同步的情况。如若出现上述情况,请重新测量并等待数据读取。';
@override
String get todayHrvMeasurementWarning => '注意:需打开健康里的权限,同时关闭省电模式。';
@override
String get todayStressStatusWhatTitle => '什么是综合压力状态?';
@override
String get todayStressStatusWhatDescription1 =>
'DoubleFeel 会结合你过去 30 天的 HRV(心率变异性)、静息心率以及当天的身体状态变化,综合评估你的整体压力水平。';
@override
String get todayStressStatusWhatDescription2 =>
'由于 HRV 会随着情绪、运动、睡眠和疲劳不断波动,单次数据参考意义有限,因此我们更建议关注一整天的综合压力状态,让结果更稳定、更有参考价值。综合压力不仅能帮助你了解自己的身体状态,也能让亲密联系人更及时地关注你的变化。';
@override
String get todayStressStatusWhyHrvTitle => '为什么要参考 HRV(心率变异性)?';
@override
String get todayStressStatusWhyHrvDescription => 'HRV 是衡量身体压力与恢复能力的重要指标。';
@override
String get todayStressStatusUsually => '通常来说:';
@override
String get todayStressStatusHrvHigher => '· HRV 越高,代表身体恢复状态越好';
@override
String get todayStressStatusHrvLower => '· HRV 越低,可能意味着疲劳、压力或睡眠不足';
@override
String get todayStressStatusHrvChangesFast => '· HRV 变化较快,更适合观察短时间内的身体状态变化。';
@override
String get todayStressStatusAppWatchDifferenceTitle =>
'手机 App 与 Apple Watch 显示的压力状态有什么区别?';
@override
String get todayStressStatusAppWatchDifferenceApp =>
'手机 App 首页显示的是当天的综合压力状态,会综合分析 HRV、静息心率与整体趋势。';
@override
String get todayStressStatusAppWatchDifferenceWatch =>
'Apple Watch 显示的是最近一次的实时压力状态,更适合快速查看当前身体变化。';
@override
String get todayStressStatusWaitingDataTitle => '为什么会出现“等待数据”?';
@override
String get todayStressStatusWaitingDataDescription1 =>
'“等待数据”代表当前采集到的数据量不足,暂时无法生成可靠的压力评估。';
@override
String get todayStressStatusWaitingDataDescription2 =>
'请继续佩戴 Apple Watch,等待系统自动采集数据。';
@override
String get todayStressStatusWaitingDataReasonsIntro => '可能原因包括:';
@override
String get todayStressStatusWaitingDataReason1 => '1. HRV 数据采样不足';
@override
String get todayStressStatusWaitingDataReason2 => '2. 缺少静息心率数据';
@override
String get todayStressStatusWaitingDataReason3 => '3. Apple Watch 佩戴时间较短';
@override
String get todayStressStatusWaitingDataReason4 => '4. Apple Health 权限未开启';
@override
String get todayHrvPrincipleHowMeasureTitle => 'DoubleFeel 如何测量压力状态?';
@override
String get todayHrvPrincipleHowMeasureDescription1 =>
'当你正常佩戴 Apple Watch 时,系统会自动采集你的心率数据,并同步至 Apple Health。';
@override
String get todayHrvPrincipleHowMeasureDescription2 =>
'DoubleFeel 会基于这些数据计算 HRV(心率变异性)相关指标,用于评估你的身体压力与恢复状态。';
@override
String get todayHrvPrincipleHowMeasureDescription3 =>
'HRV 对压力、疲劳、睡眠、情绪与身体恢复都非常敏感,因此它能够帮助我们更早发现身体状态变化。';
@override
String get todayHrvPrincipleHowMeasureDescription4 =>
'为了让结果更准确,DoubleFeel 会将你当前的 HRV 状态与过去 30 天的个人平均水平进行对比,而不是直接与其他人比较。';
@override
String get todayRealtimeStressWhatTitle => '什么是实时压力?';
@override
String get todayRealtimeStressWhatDescription1 =>
'实时压力是 DoubleFeel 根据你当前的 HRV、心率状态与个人历史数据变化,动态生成的身体压力指标。';
@override
String get todayRealtimeStressWhatDescription2 =>
'压力值越高,代表你的身体状态相比平时偏离越明显,可能正处于疲劳、恢复不足或高压力状态。';
@override
String get todayRealtimeStressWhatDescription3 =>
'它能够帮助你更快发现身体变化,并及时调整休息、运动与生活节奏。';
@override
String get todayRealtimeStressDivisionTitle => '实时压力如何划分?';
@override
String get todayRealtimeStressDivisionIntro => '实时压力以百分比形式展示:';
@override
String get todayRealtimeStressExcellentRange => '状态优秀:1%~20%';
@override
String get todayRealtimeStressNormalRange => '状态正常:21%~60%';
@override
String get todayRealtimeStressCautionRange => '注意压力:61%~80%';
@override
String get todayRealtimeStressOverloadRange => '压力过载:81%~100%';
@override
String get todayRealtimeStressExcellentDescription => '身体恢复状态较好,整体较放松。';
@override
String get todayRealtimeStressNormalDescription => '身体处于正常波动范围。';
@override
String get todayRealtimeStressCautionDescription => '身体可能正在积累压力,需要适当休息与恢复。';
@override
String get todayRealtimeStressOverloadDescription =>
'身体压力明显偏高,建议减少负荷、注意睡眠与恢复。';
@override
String get todayRealtimeStressDivisionBaseline =>
'以上区间会结合你的个人基线动态调整,不同用户之间并不直接比较。';
@override
String get todayRealtimeStressDivisionAwake => '此外,实时压力主要反映清醒状态下的身体压力变化。';
@override
String get todayRealtimeStressLowBetterTitle => '实时压力越低越好吗?';
@override
String get todayRealtimeStressLowBetterNo => '并不一定。';
@override
String get todayRealtimeStressLowBetterType => '身体压力分为“正常压力”与“异常压力”。';
@override
String get todayRealtimeStressLowBetterExample =>
'例如:运动期间或运动后,实时压力短时间升高属于正常恢复反应;工作专注、情绪兴奋时,压力也可能暂时升高,这些都属于正常的身体调节。';
@override
String get todayRealtimeStressLowBetterHighStress =>
'但如果在静息、久坐或睡眠不足的情况下,压力长期偏高,则可能意味着身体疲劳、心理压力较大、睡眠恢复不足、运动恢复不充分、摄入过多咖啡因、酒精或刺激物、身体可能处于不适状态。';
@override
String get todayRealtimeStressLowBetterTrend =>
'DoubleFeel 更关注的是你的长期变化趋势,而不是单次波动。';
@override
String get todayRealtimeStressScenarioTitle => 'HRV 与实时压力适用场景?';
@override
String get todayRealtimeStressScenarioHrvDefault =>
'在 Apple Watch 的默认设置下,HRV 每 2~5 小时更新一次。';
@override
String get todayRealtimeStressScenarioRegionLimit =>
'在部分地区,由于 Apple Watch 的呼吸功能受限,HRV 的更新频率可能会受到影响,并且开启呼吸功能后也会消耗更多电量。';
@override
String get todayRealtimeStressScenarioIntro =>
'为了解决 HRV 更新间隔较长的问题,DoubleFeel 设计了实时压力功能:';
@override
String get todayRealtimeStressScenarioUpdateEvery6Min => '· 实时压力每 6 分钟更新一次';
@override
String get todayRealtimeStressScenarioTimely => '· 可以更及时地反映身体状态变化';
@override
String get todayRealtimeStressScenarioConsistentTrend =>
'· 在大多数情况下,实时压力趋势与 HRV 趋势是一致的';
@override
String get todayRealtimeStressScenarioSummary =>
'这样用户既能获得 HRV 的长期趋势,也能通过实时压力获得短时身体状态的参考。';
@override
String get todayFaqNoDataTitle => 'APP或表盘有没有数据怎么办?';
@override
String get todayFaqNoDataDescription1 =>
'1. 确认苹果手表系统在10.0以上,手机系统在14以上,系统版本可在「关于本机」内查看。';
@override
String get todayFaqNoDataDescription2 =>
'2. 确认是否开启所有权限:手机「健康」-「共享」-「app」-「DoubleFeel」-「打开所有权限」。';
@override
String get todayFaqNoDataDescription3 =>
'3. 确认设备是否处于省电模式、低电量状态或手表佩戴未贴紧,以上情况会影响手表数据采集。';
@override
String get todayFaqContactPrefix => '如以上均检查无问题,可以';
@override
String get todayFaqContactAction => '联系我们';
@override
String get todayFaqContactSuffix => '。';
@override
String get todayFaqWatchNoNotificationTitle => '手表无法收到状态通知?';
@override
String get todayFaqWatchNoNotificationDescription1 =>
'苹果手表和手机的通知展示有优先级:当手机已解锁并亮屏时,通知只会在手机端展示,不会在手表上出现。';
@override
String get todayFaqWatchNoNotificationDescription2 =>
'若压力数据可正常显示和自动更新,但手表未收到通知,可尝试以下操作:';
@override
String get todayFaqWatchNoNotificationCheckPhoneNotification =>
'1. 检查手机是否打开通知(设置-DoubleFeel-通知)。';
@override
String get todayFaqWatchNoNotificationCheckPhoneBackgroundRefresh =>
'2. 检查手机是否打开后台App刷新(设置-DoubleFeel-后台App刷新)。';
@override
String get todayFaqWatchNoNotificationCheckWatchBackgroundRefresh =>
'3. 检查手表是否打开后台App刷新(设置-通用-后台App刷新,并确保DoubleFeel开启)。';
@override
String get todayFaqWatchNoNotificationCheckModes =>
'4. 确保未处于低电量/专注/勿扰/剧院/睡眠等模式。';
@override
String get todayFaqWatchNoNotificationReinstall =>
'5. 重装DoubleFeel 并重启AppleWatch与iPhone。';
@override
String get todayFaqWatchFaceDelayTitle => '手表表盘数据不更新或有延迟?';
@override
String get todayFaqWatchFaceDelayDescription1 =>
'由于苹果系统限制,所有手表表盘(第三方或官方)都会存在几分钟至半小时的延迟,开发者无法控制刷新频率。';
@override
String get todayFaqWatchFaceDelayIfOverOneHour => '若手机数据刷新后超过1小时表盘仍未更新:';
@override
String get todayFaqWatchFaceDelayOpenWatchApp =>
'请在手表上手动打开DoubleFeel,等待约1分钟。';
@override
String get todayFaqWatchFaceDelayIfStill => '若仍未更新:';
@override
String get todayFaqWatchFaceDelayRestartApp => '关闭DoubleFeel后台进程并重启。';
@override
String get todayFaqWatchFaceDelayCheckIntro => '仍无效时,请检查:';
@override
String get todayFaqWatchFaceDelayCheckData => '· 手机和手表app是否可正常看到HRV数据。';
@override
String get todayFaqWatchFaceDelayCheckPhoneHealth =>
'· 确保手机端「iOS设置-隐私与安全性-健康-DoubleFeel」全部授权。';
@override
String get todayFaqWatchFaceDelayCheckWatchHealth =>
'· 确保手表端「设置-健康-数据来源、App和服务-DoubleFeel」全部授权。';
@override
String get todayFaqWatchFaceDelayCheckBackgroundRefresh =>
'· 确认AppleWatch-设置-通用-后台App刷新中DoubleFeel已开启。';
@override
String get todayFaqWatchFaceDelayRestartWatch =>
'· 若仍未自动刷新,请重启手表。长时间运行或后台占用过高可能导致表盘暂停更新。';
@override
String get todayFaqWatchFaceBlackScreenTitle => '手表表盘出现黑屏?';
@override
String get todayFaqWatchFaceBlackScreenDescription =>
'若添加专属互动表盘后出现黑屏(仅显示时间和日期),可长按表盘,点击「编辑」,左滑至「复杂功能」,选择 DoubleFeel,然后按需选择各组件重新添加。';
}
... ...