Showing
9 changed files
with
92 additions
and
36 deletions
| @@ -213,11 +213,11 @@ class TodayController extends GetMaterialController { | @@ -213,11 +213,11 @@ class TodayController extends GetMaterialController { | ||
| 213 | 213 | ||
| 214 | void changeDate(DateTime date, {DateTime? focused}) { | 214 | void changeDate(DateTime date, {DateTime? focused}) { |
| 215 | final normalizedDate = _clampDate(date); | 215 | final normalizedDate = _clampDate(date); |
| 216 | - // if (!DateUtils.isSameDay(date, lastSelectableDay.value) && | ||
| 217 | - // !_userStateService.isVip) { | ||
| 218 | - // toPremiumPage('今日-查看非当日数据'); | ||
| 219 | - // return; | ||
| 220 | - // } | 216 | + if (!DateUtils.isSameDay(date, lastSelectableDay.value) && |
| 217 | + !_userStateService.isVip) { | ||
| 218 | + toPremiumPage('今日-查看非当日数据'); | ||
| 219 | + return; | ||
| 220 | + } | ||
| 221 | selectedDate.value = normalizedDate; | 221 | selectedDate.value = normalizedDate; |
| 222 | focusedDay.value = _clampDate(focused ?? normalizedDate); | 222 | focusedDay.value = _clampDate(focused ?? normalizedDate); |
| 223 | } | 223 | } |
| @@ -339,6 +339,7 @@ class TodayController extends GetMaterialController { | @@ -339,6 +339,7 @@ class TodayController extends GetMaterialController { | ||
| 339 | }, | 339 | }, |
| 340 | ); | 340 | ); |
| 341 | } else { | 341 | } else { |
| 342 | + unawaited(loadDataForDate(selectedDate.value)); | ||
| 342 | await checkUploadedStatus(firstTime, result); | 343 | await checkUploadedStatus(firstTime, result); |
| 343 | } | 344 | } |
| 344 | } catch (e) {} | 345 | } catch (e) {} |
| @@ -453,7 +454,7 @@ class TodayController extends GetMaterialController { | @@ -453,7 +454,7 @@ class TodayController extends GetMaterialController { | ||
| 453 | hrvAnnotations.clear(); | 454 | hrvAnnotations.clear(); |
| 454 | 455 | ||
| 455 | v2HealthData.value = null; | 456 | v2HealthData.value = null; |
| 456 | - v2StressScore.value = null; | 457 | + // v2StressScore.value = null; |
| 457 | } | 458 | } |
| 458 | 459 | ||
| 459 | toTrendHrvPage() { | 460 | toTrendHrvPage() { |
| @@ -646,7 +647,7 @@ class TodayController extends GetMaterialController { | @@ -646,7 +647,7 @@ class TodayController extends GetMaterialController { | ||
| 646 | checkAddFriendVisible(); | 647 | checkAddFriendVisible(); |
| 647 | checkHrvAdBannerVisible(); | 648 | checkHrvAdBannerVisible(); |
| 648 | checkHealthDataAuthCardVisible(); | 649 | checkHealthDataAuthCardVisible(); |
| 649 | - unawaited(loadDataForDate(selectedDate.value)); | 650 | + // unawaited(loadDataForDate(selectedDate.value)); |
| 650 | } | 651 | } |
| 651 | } | 652 | } |
| 652 | 653 | ||
| @@ -660,6 +661,6 @@ class TodayController extends GetMaterialController { | @@ -660,6 +661,6 @@ class TodayController extends GetMaterialController { | ||
| 660 | checkAddFriendVisible(); | 661 | checkAddFriendVisible(); |
| 661 | checkHrvAdBannerVisible(); | 662 | checkHrvAdBannerVisible(); |
| 662 | checkHealthDataAuthCardVisible(); | 663 | checkHealthDataAuthCardVisible(); |
| 663 | - await loadDataForDate(selectedDate.value); | 664 | + // await loadDataForDate(selectedDate.value); |
| 664 | } | 665 | } |
| 665 | } | 666 | } |
| @@ -37,12 +37,9 @@ class MyTab extends GetView<MyController> { | @@ -37,12 +37,9 @@ class MyTab extends GetView<MyController> { | ||
| 37 | 37 | ||
| 38 | return ListView( | 38 | return ListView( |
| 39 | physics: const ClampingScrollPhysics(), | 39 | physics: const ClampingScrollPhysics(), |
| 40 | - padding: EdgeInsets.fromLTRB( | ||
| 41 | - 16, | ||
| 42 | - 59, | ||
| 43 | - 16, | ||
| 44 | - 150 + MediaQuery.paddingOf(context).bottom, | ||
| 45 | - ), | 40 | + padding: EdgeInsets.fromLTRB(16, 59, 16, 0 |
| 41 | + // 150 + MediaQuery.paddingOf(context).bottom, | ||
| 42 | + ), | ||
| 46 | children: [ | 43 | children: [ |
| 47 | Padding( | 44 | Padding( |
| 48 | padding: const EdgeInsets.only(left: 8), | 45 | padding: const EdgeInsets.only(left: 8), |
| @@ -68,16 +65,16 @@ class MyTab extends GetView<MyController> { | @@ -68,16 +65,16 @@ class MyTab extends GetView<MyController> { | ||
| 68 | title: context.l10n.help, | 65 | title: context.l10n.help, |
| 69 | onTap: () => Get.toNamed(Routes.HELP), | 66 | onTap: () => Get.toNamed(Routes.HELP), |
| 70 | ), | 67 | ), |
| 71 | - const SizedBox(height: 12), | ||
| 72 | - _SettingsRow( | ||
| 73 | - title: 'Apple Health Upload 测试', | ||
| 74 | - onTap: () { | ||
| 75 | - controller.testAppleHealthUpload(); | ||
| 76 | - }, | ||
| 77 | - ), | ||
| 78 | if (environmentConfig.isDebug) ...[ | 68 | if (environmentConfig.isDebug) ...[ |
| 79 | const SizedBox(height: 12), | 69 | const SizedBox(height: 12), |
| 80 | _SettingsRow( | 70 | _SettingsRow( |
| 71 | + title: 'Apple Health Upload 测试', | ||
| 72 | + onTap: () { | ||
| 73 | + controller.testAppleHealthUpload(); | ||
| 74 | + }, | ||
| 75 | + ), | ||
| 76 | + const SizedBox(height: 12), | ||
| 77 | + _SettingsRow( | ||
| 81 | title: 'Developer options', | 78 | title: 'Developer options', |
| 82 | onTap: () { | 79 | onTap: () { |
| 83 | Get.toNamed(Routes.DEVELOPER_OPTIONS); | 80 | Get.toNamed(Routes.DEVELOPER_OPTIONS); |
| @@ -141,7 +141,8 @@ class TodayTabBody extends StatelessWidget { | @@ -141,7 +141,8 @@ class TodayTabBody extends StatelessWidget { | ||
| 141 | child: CircularProgressIndicator()), | 141 | child: CircularProgressIndicator()), |
| 142 | ) | 142 | ) |
| 143 | : Image.asset( | 143 | : Image.asset( |
| 144 | - controller.v2StressScore.value!.stateBg(), | 144 | + controller.v2StressScore.value?.stateBg() ?? |
| 145 | + 'assets/images/today/bg_stress_state_0.png', | ||
| 145 | fit: BoxFit.cover, | 146 | fit: BoxFit.cover, |
| 146 | width: Get.width, | 147 | width: Get.width, |
| 147 | height: Get.width / 375 * 345, | 148 | height: Get.width / 375 * 345, |
| @@ -515,6 +515,15 @@ class _HrvLineChartState extends State<_HrvLineChart> { | @@ -515,6 +515,15 @@ class _HrvLineChartState extends State<_HrvLineChart> { | ||
| 515 | Timer? _hrvTooltipTimer; | 515 | Timer? _hrvTooltipTimer; |
| 516 | 516 | ||
| 517 | @override | 517 | @override |
| 518 | + void didUpdateWidget(covariant _HrvLineChart oldWidget) { | ||
| 519 | + super.didUpdateWidget(oldWidget); | ||
| 520 | + if (widget.spots != oldWidget.spots) { | ||
| 521 | + _hrvTooltipTimer?.cancel(); | ||
| 522 | + _hrvShowingSpots = []; | ||
| 523 | + } | ||
| 524 | + } | ||
| 525 | + | ||
| 526 | + @override | ||
| 518 | void dispose() { | 527 | void dispose() { |
| 519 | _hrvTooltipTimer?.cancel(); | 528 | _hrvTooltipTimer?.cancel(); |
| 520 | super.dispose(); | 529 | super.dispose(); |
| @@ -614,6 +623,8 @@ class _HrvLineChartState extends State<_HrvLineChart> { | @@ -614,6 +623,8 @@ class _HrvLineChartState extends State<_HrvLineChart> { | ||
| 614 | ShowingTooltipIndicators(_hrvShowingSpots), | 623 | ShowingTooltipIndicators(_hrvShowingSpots), |
| 615 | ], | 624 | ], |
| 616 | lineTouchData: LineTouchData( | 625 | lineTouchData: LineTouchData( |
| 626 | + getTouchLineStart: (barData, spotIndex) => 0, | ||
| 627 | + getTouchLineEnd: (barData, spotIndex) => 90, | ||
| 617 | handleBuiltInTouches: false, | 628 | handleBuiltInTouches: false, |
| 618 | touchSpotThreshold: 20.0, | 629 | touchSpotThreshold: 20.0, |
| 619 | touchCallback: | 630 | touchCallback: |
| @@ -673,6 +684,8 @@ class _HrvLineChartState extends State<_HrvLineChart> { | @@ -673,6 +684,8 @@ class _HrvLineChartState extends State<_HrvLineChart> { | ||
| 673 | }, | 684 | }, |
| 674 | touchTooltipData: LineTouchTooltipData( | 685 | touchTooltipData: LineTouchTooltipData( |
| 675 | tooltipRoundedRadius: 8, | 686 | tooltipRoundedRadius: 8, |
| 687 | + showOnTopOfTheChartBoxArea: true, | ||
| 688 | + tooltipMargin: 6, | ||
| 676 | tooltipBorder: BorderSide.none, | 689 | tooltipBorder: BorderSide.none, |
| 677 | maxContentWidth: 400, | 690 | maxContentWidth: 400, |
| 678 | fitInsideHorizontally: true, | 691 | fitInsideHorizontally: true, |
| @@ -737,6 +750,18 @@ class _StressBarChartState extends State<_StressBarChart> { | @@ -737,6 +750,18 @@ class _StressBarChartState extends State<_StressBarChart> { | ||
| 737 | Timer? _stressTooltipTimer; | 750 | Timer? _stressTooltipTimer; |
| 738 | 751 | ||
| 739 | @override | 752 | @override |
| 753 | + void didUpdateWidget(covariant _StressBarChart oldWidget) { | ||
| 754 | + super.didUpdateWidget(oldWidget); | ||
| 755 | + if (widget.selectedDate != oldWidget.selectedDate || | ||
| 756 | + widget.stressPoints != oldWidget.stressPoints) { | ||
| 757 | + _stressTooltipTimer?.cancel(); | ||
| 758 | + setState(() { | ||
| 759 | + _stressTouchedGroupIndex = null; | ||
| 760 | + }); | ||
| 761 | + } | ||
| 762 | + } | ||
| 763 | + | ||
| 764 | + @override | ||
| 740 | void dispose() { | 765 | void dispose() { |
| 741 | _stressTooltipTimer?.cancel(); | 766 | _stressTooltipTimer?.cancel(); |
| 742 | super.dispose(); | 767 | super.dispose(); |
| @@ -749,12 +774,14 @@ class _StressBarChartState extends State<_StressBarChart> { | @@ -749,12 +774,14 @@ class _StressBarChartState extends State<_StressBarChart> { | ||
| 749 | // 右轴 reservedSize=22,不占用空间设为 0.0 | 774 | // 右轴 reservedSize=22,不占用空间设为 0.0 |
| 750 | const rightAxisWidth = 0.0; | 775 | const rightAxisWidth = 0.0; |
| 751 | const slotSec = 6 * 60; | 776 | const slotSec = 6 * 60; |
| 752 | - final slotCount = (widget.maxSeconds / slotSec).ceil().clamp(1, 9999); | 777 | + // 关键:由于循环条件是 sec <= maxSec,实际绘制的组数(groups.length)为总槽数 + 1 |
| 778 | + final slotCount = (widget.maxSeconds / slotSec).round() + 1; | ||
| 753 | const double groupsSpace = 0.25; // 设置间隔为 1 像素 | 779 | const double groupsSpace = 0.25; // 设置间隔为 1 像素 |
| 754 | - final barWidth = (constraints.maxWidth - | ||
| 755 | - rightAxisWidth - | ||
| 756 | - (groupsSpace * (slotCount - 1))) / | ||
| 757 | - slotCount; | 780 | + // 因为 BarChart 外层 Container 有 padding: EdgeInsets.only(right: 3),所以其实际宽度减少了 3.0 |
| 781 | + final chartWidth = constraints.maxWidth - 3.0; | ||
| 782 | + final barWidth = | ||
| 783 | + (chartWidth - rightAxisWidth - (groupsSpace * (slotCount - 1))) / | ||
| 784 | + slotCount; | ||
| 758 | // 根据 V2SleepTimeRange 计算多段睡眠区间的 Positioned widgets | 785 | // 根据 V2SleepTimeRange 计算多段睡眠区间的 Positioned widgets |
| 759 | final sleepWidgets = <Widget>[]; | 786 | final sleepWidgets = <Widget>[]; |
| 760 | 787 | ||
| @@ -873,6 +900,25 @@ class _StressBarChartState extends State<_StressBarChart> { | @@ -873,6 +900,25 @@ class _StressBarChartState extends State<_StressBarChart> { | ||
| 873 | final gridBottom = chartHeight - 20.0; | 900 | final gridBottom = chartHeight - 20.0; |
| 874 | final gridHeight = gridBottom - gridTop; | 901 | final gridHeight = gridBottom - gridTop; |
| 875 | 902 | ||
| 903 | + // 自定义指示线 (只在 Stack 层手绘一条垂直灰色指示线,与柱子对齐,高度到达顶部以与 tooltip 连上) | ||
| 904 | + Positioned? customIndicator; | ||
| 905 | + if (_stressTouchedGroupIndex != null) { | ||
| 906 | + final stepWidth = barWidth + groupsSpace; | ||
| 907 | + final centerOfBar = | ||
| 908 | + _stressTouchedGroupIndex! * stepWidth + (barWidth / 2); | ||
| 909 | + customIndicator = Positioned( | ||
| 910 | + left: centerOfBar - 1.0, // 2px 宽度,居中 | ||
| 911 | + width: 2.0, | ||
| 912 | + top: 16.0, // 向上延展以连接 tooltip 底部 | ||
| 913 | + bottom: chartHeight - gridBottom, // 修正:bottom 指的是距离 Stack 底部的像素值 | ||
| 914 | + child: IgnorePointer( | ||
| 915 | + child: ColoredBox( | ||
| 916 | + color: context.colors.textTertiary.withAlpha(125), | ||
| 917 | + ), | ||
| 918 | + ), | ||
| 919 | + ); | ||
| 920 | + } | ||
| 921 | + | ||
| 876 | return Stack( | 922 | return Stack( |
| 877 | clipBehavior: Clip.none, | 923 | clipBehavior: Clip.none, |
| 878 | children: [ | 924 | children: [ |
| @@ -1039,7 +1085,9 @@ class _StressBarChartState extends State<_StressBarChart> { | @@ -1039,7 +1085,9 @@ class _StressBarChartState extends State<_StressBarChart> { | ||
| 1039 | tooltipBorder: BorderSide.none, | 1085 | tooltipBorder: BorderSide.none, |
| 1040 | maxContentWidth: 400, | 1086 | maxContentWidth: 400, |
| 1041 | fitInsideHorizontally: true, | 1087 | fitInsideHorizontally: true, |
| 1042 | - fitInsideVertically: false, | 1088 | + fitInsideVertically: |
| 1089 | + false, // 允许 tooltip 超出 BarChart 顶边界(绘制在 18px 的 top margin 区域内) | ||
| 1090 | + tooltipMargin: 6, // 调整为和折线图一样的 6 像素空隙 | ||
| 1043 | getTooltipColor: (touchedSpot) => const Color(0xFFF3F3F3), | 1091 | getTooltipColor: (touchedSpot) => const Color(0xFFF3F3F3), |
| 1044 | tooltipPadding: const EdgeInsets.only( | 1092 | tooltipPadding: const EdgeInsets.only( |
| 1045 | left: 12, | 1093 | left: 12, |
| @@ -1057,7 +1105,8 @@ class _StressBarChartState extends State<_StressBarChart> { | @@ -1057,7 +1105,8 @@ class _StressBarChartState extends State<_StressBarChart> { | ||
| 1057 | color: Colors.white, | 1105 | color: Colors.white, |
| 1058 | fontWeight: FontWeight.bold, | 1106 | fontWeight: FontWeight.bold, |
| 1059 | ), | 1107 | ), |
| 1060 | - children: widget.getTooltip(rod, group.x, state), | 1108 | + children: widget.getTooltip( |
| 1109 | + group.barRods[0], group.x, state), | ||
| 1061 | textAlign: TextAlign.start, | 1110 | textAlign: TextAlign.start, |
| 1062 | ); | 1111 | ); |
| 1063 | }, | 1112 | }, |
| @@ -1066,6 +1115,8 @@ class _StressBarChartState extends State<_StressBarChart> { | @@ -1066,6 +1115,8 @@ class _StressBarChartState extends State<_StressBarChart> { | ||
| 1066 | ), | 1115 | ), |
| 1067 | ), | 1116 | ), |
| 1068 | ), | 1117 | ), |
| 1118 | + if (customIndicator != null) | ||
| 1119 | + customIndicator, // 将指示线移动到 Container (BarChart) 之后绘制,防止被盖住 | ||
| 1069 | ...sleepWidgets, | 1120 | ...sleepWidgets, |
| 1070 | // 手绘 100、50、0 标签在对应的横线上方 | 1121 | // 手绘 100、50、0 标签在对应的横线上方 |
| 1071 | Positioned( | 1122 | Positioned( |
| @@ -1126,7 +1177,8 @@ class _StressBarChartState extends State<_StressBarChart> { | @@ -1126,7 +1177,8 @@ class _StressBarChartState extends State<_StressBarChart> { | ||
| 1126 | final isTouched = groupIndex == _stressTouchedGroupIndex; | 1177 | final isTouched = groupIndex == _stressTouchedGroupIndex; |
| 1127 | groups.add(BarChartGroupData( | 1178 | groups.add(BarChartGroupData( |
| 1128 | x: sec, | 1179 | x: sec, |
| 1129 | - showingTooltipIndicators: isTouched ? [0] : [], | 1180 | + barsSpace: 0, |
| 1181 | + showingTooltipIndicators: isTouched ? [1] : [], | ||
| 1130 | barRods: [ | 1182 | barRods: [ |
| 1131 | BarChartRodData( | 1183 | BarChartRodData( |
| 1132 | toY: entry != null ? entry.value.toDouble() : 0, | 1184 | toY: entry != null ? entry.value.toDouble() : 0, |
| @@ -1136,6 +1188,11 @@ class _StressBarChartState extends State<_StressBarChart> { | @@ -1136,6 +1188,11 @@ class _StressBarChartState extends State<_StressBarChart> { | ||
| 1136 | : Colors.transparent, | 1188 | : Colors.transparent, |
| 1137 | borderRadius: BorderRadius.circular(barWidth / 2), | 1189 | borderRadius: BorderRadius.circular(barWidth / 2), |
| 1138 | ), | 1190 | ), |
| 1191 | + BarChartRodData( | ||
| 1192 | + toY: 100, // 用于固定 tooltip 在顶部 | ||
| 1193 | + width: 0, // 0 宽度,不占空间 | ||
| 1194 | + color: Colors.transparent, | ||
| 1195 | + ), | ||
| 1139 | ], | 1196 | ], |
| 1140 | )); | 1197 | )); |
| 1141 | } | 1198 | } |
| @@ -551,7 +551,7 @@ | @@ -551,7 +551,7 @@ | ||
| 551 | "filming": "Filming", | 551 | "filming": "Filming", |
| 552 | "unlockTheProVersion": "Unlock the Pro Version", | 552 | "unlockTheProVersion": "Unlock the Pro Version", |
| 553 | "embarkOnAJourneyOfStressAwarenessAndWellnessSupport": "Embark on a Journey of Stress Awareness and Wellness Support", | 553 | "embarkOnAJourneyOfStressAwarenessAndWellnessSupport": "Embark on a Journey of Stress Awareness and Wellness Support", |
| 554 | - "sharePartnerCodeTemplate": "Hey ❤️ I found an app called DoubleFeel!\nIt helps us care for each other — track stress and sleep, view HRV and physical status, and stay updated on each other's health in real-time.\nCome join me 👉 https://doublefeel.cn/\nMy friend ID: {inviteCode}", | 554 | + "sharePartnerCodeTemplate": "Hey ❤️ I found an app called DoubleFeel!\nIt helps us care for each other — track stress and sleep, view HRV and physical status, and stay updated on each other's health in real-time.\nCome join me 👉 https://apps.apple.com/cn/app/doublefeel-%E5%8F%8C%E4%BA%BA%E6%83%85%E7%BB%AA%E5%85%B1%E4%BA%ABhrv%E5%8E%8B%E5%8A%9B%E6%B0%B4%E5%B9%B3%E8%87%AA%E6%B5%8B%E7%9D%A1%E7%9C%A0%E8%AE%B0%E5%BD%95/id6747254434\nMy friend ID: {inviteCode}", |
| 555 | "@sharePartnerCodeTemplate": { | 555 | "@sharePartnerCodeTemplate": { |
| 556 | "description": "Share partner code template", | 556 | "description": "Share partner code template", |
| 557 | "placeholders": { | 557 | "placeholders": { |
| @@ -693,4 +693,4 @@ | @@ -693,4 +693,4 @@ | ||
| 693 | "feedbackSubmitSuccessTitle": "Feedback submitted successfully", | 693 | "feedbackSubmitSuccessTitle": "Feedback submitted successfully", |
| 694 | "feedbackSubmitSuccessMessage": "Thank you for your feedback. If further communication is needed, we will contact you via the email address you left as soon as possible. Please keep an eye on your inbox.", | 694 | "feedbackSubmitSuccessMessage": "Thank you for your feedback. If further communication is needed, we will contact you via the email address you left as soon as possible. Please keep an eye on your inbox.", |
| 695 | "feedbackSubmitSuccessConfirm": "OK" | 695 | "feedbackSubmitSuccessConfirm": "OK" |
| 696 | -} | 696 | +} |
| @@ -930,7 +930,7 @@ | @@ -930,7 +930,7 @@ | ||
| 930 | "filming": "拍摄", | 930 | "filming": "拍摄", |
| 931 | "unlockTheProVersion": "解锁专业版", | 931 | "unlockTheProVersion": "解锁专业版", |
| 932 | "embarkOnAJourneyOfStressAwarenessAndWellnessSupport": "开启压力预警与健康陪伴之旅", | 932 | "embarkOnAJourneyOfStressAwarenessAndWellnessSupport": "开启压力预警与健康陪伴之旅", |
| 933 | - "sharePartnerCodeTemplate": "嘿 ❤️ 我发现了一个叫 DoubleFeel 的 App!\n它可以帮我们互相关心 — 记录压力和睡眠、查看 HRV 与身体状态、及时了解彼此的健康状况。\n快来一起使用吧 👉 https://doublefeel.cn/\n我的好友id:{inviteCode}", | 933 | + "sharePartnerCodeTemplate": "嘿 ❤️ 我发现了一个叫 DoubleFeel 的 App!\n它可以帮我们互相关心 — 记录压力和睡眠、查看 HRV 与身体状态、及时了解彼此的健康状况。\n快来一起使用吧 👉 https://apps.apple.com/cn/app/doublefeel-%E5%8F%8C%E4%BA%BA%E6%83%85%E7%BB%AA%E5%85%B1%E4%BA%ABhrv%E5%8E%8B%E5%8A%9B%E6%B0%B4%E5%B9%B3%E8%87%AA%E6%B5%8B%E7%9D%A1%E7%9C%A0%E8%AE%B0%E5%BD%95/id6747254434\n我的好友id:{inviteCode}", |
| 934 | "@sharePartnerCodeTemplate": { | 934 | "@sharePartnerCodeTemplate": { |
| 935 | "description": "分享好友邀请码文案模板", | 935 | "description": "分享好友邀请码文案模板", |
| 936 | "placeholders": { | 936 | "placeholders": { |
| @@ -3408,7 +3408,7 @@ abstract class AppLocalizations { | @@ -3408,7 +3408,7 @@ abstract class AppLocalizations { | ||
| 3408 | /// 分享好友邀请码文案模板 | 3408 | /// 分享好友邀请码文案模板 |
| 3409 | /// | 3409 | /// |
| 3410 | /// In zh, this message translates to: | 3410 | /// In zh, this message translates to: |
| 3411 | - /// **'嘿 ❤️ 我发现了一个叫 DoubleFeel 的 App!\n它可以帮我们互相关心 — 记录压力和睡眠、查看 HRV 与身体状态、及时了解彼此的健康状况。\n快来一起使用吧 👉 https://doublefeel.cn/\n我的好友id:{inviteCode}'** | 3411 | + /// **'嘿 ❤️ 我发现了一个叫 DoubleFeel 的 App!\n它可以帮我们互相关心 — 记录压力和睡眠、查看 HRV 与身体状态、及时了解彼此的健康状况。\n快来一起使用吧 👉 https://apps.apple.com/cn/app/doublefeel-%E5%8F%8C%E4%BA%BA%E6%83%85%E7%BB%AA%E5%85%B1%E4%BA%ABhrv%E5%8E%8B%E5%8A%9B%E6%B0%B4%E5%B9%B3%E8%87%AA%E6%B5%8B%E7%9D%A1%E7%9C%A0%E8%AE%B0%E5%BD%95/id6747254434\n我的好友id:{inviteCode}'** |
| 3412 | String sharePartnerCodeTemplate(String inviteCode); | 3412 | String sharePartnerCodeTemplate(String inviteCode); |
| 3413 | 3413 | ||
| 3414 | /// No description provided for @bindPartnerIdNotExistTitle. | 3414 | /// No description provided for @bindPartnerIdNotExistTitle. |
| @@ -1914,7 +1914,7 @@ class AppLocalizationsEn extends AppLocalizations { | @@ -1914,7 +1914,7 @@ class AppLocalizationsEn extends AppLocalizations { | ||
| 1914 | 1914 | ||
| 1915 | @override | 1915 | @override |
| 1916 | String sharePartnerCodeTemplate(String inviteCode) { | 1916 | String sharePartnerCodeTemplate(String inviteCode) { |
| 1917 | - return 'Hey ❤️ I found an app called DoubleFeel!\nIt helps us care for each other — track stress and sleep, view HRV and physical status, and stay updated on each other\'s health in real-time.\nCome join me 👉 https://doublefeel.cn/\nMy friend ID: $inviteCode'; | 1917 | + return 'Hey ❤️ I found an app called DoubleFeel!\nIt helps us care for each other — track stress and sleep, view HRV and physical status, and stay updated on each other\'s health in real-time.\nCome join me 👉 https://apps.apple.com/cn/app/doublefeel-%E5%8F%8C%E4%BA%BA%E6%83%85%E7%BB%AA%E5%85%B1%E4%BA%ABhrv%E5%8E%8B%E5%8A%9B%E6%B0%B4%E5%B9%B3%E8%87%AA%E6%B5%8B%E7%9D%A1%E7%9C%A0%E8%AE%B0%E5%BD%95/id6747254434\nMy friend ID: $inviteCode'; |
| 1918 | } | 1918 | } |
| 1919 | 1919 | ||
| 1920 | @override | 1920 | @override |
| @@ -1816,7 +1816,7 @@ class AppLocalizationsZh extends AppLocalizations { | @@ -1816,7 +1816,7 @@ class AppLocalizationsZh extends AppLocalizations { | ||
| 1816 | 1816 | ||
| 1817 | @override | 1817 | @override |
| 1818 | String sharePartnerCodeTemplate(String inviteCode) { | 1818 | String sharePartnerCodeTemplate(String inviteCode) { |
| 1819 | - return '嘿 ❤️ 我发现了一个叫 DoubleFeel 的 App!\n它可以帮我们互相关心 — 记录压力和睡眠、查看 HRV 与身体状态、及时了解彼此的健康状况。\n快来一起使用吧 👉 https://doublefeel.cn/\n我的好友id:$inviteCode'; | 1819 | + return '嘿 ❤️ 我发现了一个叫 DoubleFeel 的 App!\n它可以帮我们互相关心 — 记录压力和睡眠、查看 HRV 与身体状态、及时了解彼此的健康状况。\n快来一起使用吧 👉 https://apps.apple.com/cn/app/doublefeel-%E5%8F%8C%E4%BA%BA%E6%83%85%E7%BB%AA%E5%85%B1%E4%BA%ABhrv%E5%8E%8B%E5%8A%9B%E6%B0%B4%E5%B9%B3%E8%87%AA%E6%B5%8B%E7%9D%A1%E7%9C%A0%E8%AE%B0%E5%BD%95/id6747254434\n我的好友id:$inviteCode'; |
| 1820 | } | 1820 | } |
| 1821 | 1821 | ||
| 1822 | @override | 1822 | @override |
-
Please register or login to post a comment