Commit 5894b5955a6d5dd487271f8b3445d1fbcf46bcca

Authored by 刘宏哲
1 parent 5541eb49

feat(app): 修改好评弹窗逻辑

  1 +import 'package:doublefeel_flutter/core/network/api/click_event_api.dart';
1 import 'package:doublefeel_flutter/core/network/api/friend_api.dart'; 2 import 'package:doublefeel_flutter/core/network/api/friend_api.dart';
2 import 'package:get/get.dart'; 3 import 'package:get/get.dart';
3 4
@@ -55,6 +56,7 @@ void registerUserSessionDeps() { @@ -55,6 +56,7 @@ void registerUserSessionDeps() {
55 Get.put(UserApi(dioClient), permanent: true); 56 Get.put(UserApi(dioClient), permanent: true);
56 Get.put(VipApi(dioClient), permanent: true); 57 Get.put(VipApi(dioClient), permanent: true);
57 Get.put(FriendApi(dioClient), permanent: true); 58 Get.put(FriendApi(dioClient), permanent: true);
  59 + Get.put(ClickEventApi(dioClient), permanent: true);
58 Get.put<ImService>(ImServiceStub(), permanent: true); 60 Get.put<ImService>(ImServiceStub(), permanent: true);
59 Get.put( 61 Get.put(
60 ThinkingDataService(Get.find<AppEnvironmentConfig>()), 62 ThinkingDataService(Get.find<AppEnvironmentConfig>()),
@@ -33,6 +33,16 @@ ActivityBurnDurationText activityBurnDurationText( @@ -33,6 +33,16 @@ ActivityBurnDurationText activityBurnDurationText(
33 ); 33 );
34 } 34 }
35 35
  36 +ActivityBurnDurationText activityBurnMinutesText(
  37 + BuildContext context,
  38 + int? minutes,
  39 +) {
  40 + return ActivityBurnDurationText(
  41 + value: minutes?.toString() ?? '-',
  42 + unit: context.l10n.reportUnitMinute,
  43 + );
  44 +}
  45 +
36 ActivityBurnDurationText activityBurnHoursText( 46 ActivityBurnDurationText activityBurnHoursText(
37 BuildContext context, 47 BuildContext context,
38 int? hours, 48 int? hours,
@@ -19,7 +19,7 @@ class ActivityBurnSummaryCard extends StatelessWidget { @@ -19,7 +19,7 @@ class ActivityBurnSummaryCard extends StatelessWidget {
19 19
20 @override 20 @override
21 Widget build(BuildContext context) { 21 Widget build(BuildContext context) {
22 - final exercise = activityBurnDurationText( 22 + final exercise = activityBurnMinutesText(
23 context, 23 context,
24 report?.exerciseMinutes?.value, 24 report?.exerciseMinutes?.value,
25 ); 25 );
@@ -22,12 +22,16 @@ class AppReviewPromptLogic { @@ -22,12 +22,16 @@ class AppReviewPromptLogic {
22 static const _likedCooldown = Duration(days: 90); 22 static const _likedCooldown = Duration(days: 90);
23 static const _feedbackCooldown = Duration(days: 30); 23 static const _feedbackCooldown = Duration(days: 30);
24 24
25 - Future<void> maybeShowPrompt(BuildContext context) async {  
26 - if (_isShowing || !context.mounted) return; 25 + bool canShowPrompt(BuildContext context) {
  26 + if (_isShowing || !context.mounted) return false;
27 27
28 final now = DateTime.now(); 28 final now = DateTime.now();
29 final nextShowAt = _storage.appReviewPromptNextShowAt; 29 final nextShowAt = _storage.appReviewPromptNextShowAt;
30 - if (nextShowAt != null && now.isBefore(nextShowAt)) return; 30 + return nextShowAt == null || !now.isBefore(nextShowAt);
  31 + }
  32 +
  33 + Future<void> maybeShowPrompt(BuildContext context) async {
  34 + if (!canShowPrompt(context)) return;
31 35
32 _isShowing = true; 36 _isShowing = true;
33 try { 37 try {
@@ -18,6 +18,7 @@ class AppReviewPromptDialog extends StatelessWidget { @@ -18,6 +18,7 @@ class AppReviewPromptDialog extends StatelessWidget {
18 illustrationAsset: R.assetsImagesAppReviewGoodBg, 18 illustrationAsset: R.assetsImagesAppReviewGoodBg,
19 title: context.l10n.appReviewPromptTitle, 19 title: context.l10n.appReviewPromptTitle,
20 message: context.l10n.appReviewPromptMessage, 20 message: context.l10n.appReviewPromptMessage,
  21 + primaryEmoji: context.l10n.appReviewPromptLikeActionEmoji,
21 primaryText: context.l10n.appReviewPromptLikeAction, 22 primaryText: context.l10n.appReviewPromptLikeAction,
22 secondaryText: context.l10n.appReviewPromptFeedbackAction, 23 secondaryText: context.l10n.appReviewPromptFeedbackAction,
23 onPrimaryTap: () => 24 onPrimaryTap: () =>
@@ -57,12 +58,14 @@ class _ReviewPromptCard extends StatelessWidget { @@ -57,12 +58,14 @@ class _ReviewPromptCard extends StatelessWidget {
57 required this.secondaryText, 58 required this.secondaryText,
58 required this.onPrimaryTap, 59 required this.onPrimaryTap,
59 required this.onSecondaryTap, 60 required this.onSecondaryTap,
  61 + this.primaryEmoji,
60 }); 62 });
61 63
62 final double height; 64 final double height;
63 final String illustrationAsset; 65 final String illustrationAsset;
64 final String title; 66 final String title;
65 final String message; 67 final String message;
  68 + final String? primaryEmoji;
66 final String primaryText; 69 final String primaryText;
67 final String secondaryText; 70 final String secondaryText;
68 final VoidCallback onPrimaryTap; 71 final VoidCallback onPrimaryTap;
@@ -149,6 +152,7 @@ class _ReviewPromptCard extends StatelessWidget { @@ -149,6 +152,7 @@ class _ReviewPromptCard extends StatelessWidget {
149 left: 40, 152 left: 40,
150 right: 40, 153 right: 40,
151 child: _PromptButton( 154 child: _PromptButton(
  155 + emoji: primaryEmoji,
152 text: primaryText, 156 text: primaryText,
153 textColor: Colors.white, 157 textColor: Colors.white,
154 fontWeight: FontWeight.w600, 158 fontWeight: FontWeight.w600,
@@ -182,15 +186,31 @@ class _PromptButton extends StatelessWidget { @@ -182,15 +186,31 @@ class _PromptButton extends StatelessWidget {
182 required this.textColor, 186 required this.textColor,
183 required this.fontWeight, 187 required this.fontWeight,
184 required this.onTap, 188 required this.onTap,
  189 + this.emoji,
185 this.backgroundColor, 190 this.backgroundColor,
186 }); 191 });
187 192
  193 + final String? emoji;
188 final String text; 194 final String text;
189 final Color textColor; 195 final Color textColor;
190 final FontWeight fontWeight; 196 final FontWeight fontWeight;
191 final VoidCallback onTap; 197 final VoidCallback onTap;
192 final Color? backgroundColor; 198 final Color? backgroundColor;
193 199
  200 + TextStyle get _emojiStyle => TextStyle(
  201 + color: textColor,
  202 + fontSize: 18,
  203 + height: 1.2,
  204 + fontWeight: fontWeight,
  205 + );
  206 +
  207 + TextStyle get _textStyle => TextStyle(
  208 + color: textColor,
  209 + fontSize: 16,
  210 + height: 1.2,
  211 + fontWeight: fontWeight,
  212 + );
  213 +
194 @override 214 @override
195 Widget build(BuildContext context) { 215 Widget build(BuildContext context) {
196 return GestureDetector( 216 return GestureDetector(
@@ -203,18 +223,42 @@ class _PromptButton extends StatelessWidget { @@ -203,18 +223,42 @@ class _PromptButton extends StatelessWidget {
203 color: backgroundColor, 223 color: backgroundColor,
204 borderRadius: BorderRadius.circular(24), 224 borderRadius: BorderRadius.circular(24),
205 ), 225 ),
206 - child: Text(  
207 - text, 226 + padding: const EdgeInsets.symmetric(horizontal: 16),
  227 + child: _buildContent(),
  228 + ),
  229 + );
  230 + }
  231 +
  232 + Widget _buildContent() {
  233 + final emojiText = emoji;
  234 + if (emojiText == null) {
  235 + return Text(
  236 + text,
  237 + maxLines: 1,
  238 + overflow: TextOverflow.ellipsis,
  239 + style: _textStyle,
  240 + );
  241 + }
  242 +
  243 + return Row(
  244 + mainAxisAlignment: MainAxisAlignment.center,
  245 + crossAxisAlignment: CrossAxisAlignment.center,
  246 + children: [
  247 + Text(
  248 + emojiText,
208 maxLines: 1, 249 maxLines: 1,
209 - overflow: TextOverflow.ellipsis,  
210 - style: TextStyle(  
211 - color: textColor,  
212 - fontSize: 16,  
213 - height: 1.2,  
214 - fontWeight: fontWeight, 250 + style: _emojiStyle,
  251 + ),
  252 + const SizedBox(width: 2),
  253 + Flexible(
  254 + child: Text(
  255 + text,
  256 + maxLines: 1,
  257 + overflow: TextOverflow.ellipsis,
  258 + style: _textStyle,
215 ), 259 ),
216 ), 260 ),
217 - ), 261 + ],
218 ); 262 );
219 } 263 }
220 } 264 }
  1 +import 'package:doublefeel_flutter/core/constants/event_const.dart';
1 import 'package:doublefeel_flutter/data/models/friend/friend_models.dart'; 2 import 'package:doublefeel_flutter/data/models/friend/friend_models.dart';
2 import 'package:get/get.dart'; 3 import 'package:get/get.dart';
3 4
  5 +import '../../../../core/network/api/click_event_api.dart';
4 import '../../health_trend/controllers/health_trend_analytics.dart'; 6 import '../../health_trend/controllers/health_trend_analytics.dart';
5 import '../../health_trend/controllers/health_trend_control.dart'; 7 import '../../health_trend/controllers/health_trend_control.dart';
6 import '../../report_common/models/health_report_query.dart'; 8 import '../../report_common/models/health_report_query.dart';
@@ -68,5 +70,12 @@ class FriendTrendController extends GetxController with HealthTrendControl { @@ -68,5 +70,12 @@ class FriendTrendController extends GetxController with HealthTrendControl {
68 selectedTypeIndex.value, 70 selectedTypeIndex.value,
69 userRole: '好友的', 71 userRole: '好友的',
70 ); 72 );
  73 + _trackViewFriendSleepStatsIfNeeded();
  74 + }
  75 +
  76 + void _trackViewFriendSleepStatsIfNeeded() {
  77 + if (selectedTypeIndex.value != 2) return;
  78 + if (!Get.isRegistered<ClickEventApi>()) return;
  79 + Get.find<ClickEventApi>().postClickEvent(EventConst.viewFriendSleepStats);
71 } 80 }
72 } 81 }
1 import 'package:doublefeel_flutter/app/modules/friends/controllers/friend_trend_controller.dart'; 1 import 'package:doublefeel_flutter/app/modules/friends/controllers/friend_trend_controller.dart';
2 import 'package:doublefeel_flutter/app/modules/friends/controllers/friends_controller.dart'; 2 import 'package:doublefeel_flutter/app/modules/friends/controllers/friends_controller.dart';
  3 +import 'package:doublefeel_flutter/core/constants/event_const.dart';
  4 +import 'package:doublefeel_flutter/core/constants/intent_keys.dart';
  5 +import 'package:doublefeel_flutter/core/network/api/click_event_api.dart';
3 import 'package:doublefeel_flutter/core/network/api/friend_api.dart'; 6 import 'package:doublefeel_flutter/core/network/api/friend_api.dart';
4 import 'package:doublefeel_flutter/core/result/app_result.dart'; 7 import 'package:doublefeel_flutter/core/result/app_result.dart';
5 import 'package:doublefeel_flutter/core/services/thinking_data_service.dart'; 8 import 'package:doublefeel_flutter/core/services/thinking_data_service.dart';
@@ -7,14 +10,13 @@ import 'package:doublefeel_flutter/core/services/user_state_service.dart'; @@ -7,14 +10,13 @@ import 'package:doublefeel_flutter/core/services/user_state_service.dart';
7 import 'package:doublefeel_flutter/data/local/local_storage.dart'; 10 import 'package:doublefeel_flutter/data/local/local_storage.dart';
8 import 'package:doublefeel_flutter/pigeon/platform_api.g.dart'; 11 import 'package:doublefeel_flutter/pigeon/platform_api.g.dart';
9 import 'package:flutter/material.dart'; 12 import 'package:flutter/material.dart';
10 -import 'package:flutter/services.dart';  
11 import 'package:flutter/scheduler.dart'; 13 import 'package:flutter/scheduler.dart';
12 - 14 +import 'package:flutter/services.dart';
13 import 'package:get/get.dart'; 15 import 'package:get/get.dart';
14 16
15 import '../../../routes/app_pages.dart'; 17 import '../../../routes/app_pages.dart';
16 -import '../../purchase/purchase_route_args.dart';  
17 import '../../app_review_prompt/logic/app_review_prompt_logic.dart'; 18 import '../../app_review_prompt/logic/app_review_prompt_logic.dart';
  19 +import '../../purchase/purchase_route_args.dart';
18 import '../../report_common/models/report_period.dart'; 20 import '../../report_common/models/report_period.dart';
19 import 'today_controller.dart'; 21 import 'today_controller.dart';
20 import 'trend/trend_controller.dart'; 22 import 'trend/trend_controller.dart';
@@ -81,8 +83,29 @@ class HomeController extends GetxController { @@ -81,8 +83,29 @@ class HomeController extends GetxController {
81 return url.isNotEmpty; 83 return url.isNotEmpty;
82 } 84 }
83 85
84 - Future<void> maybeShowAppReviewPrompt(BuildContext context) {  
85 - return _appReviewPromptLogic.maybeShowPrompt(context); 86 + Future<void> maybeShowAppReviewPrompt(BuildContext context) async {
  87 + if (!_appReviewPromptLogic.canShowPrompt(context)) return;
  88 +
  89 + final canShowPrompt = await _hasReviewPromptClickEvent();
  90 + if (!canShowPrompt) return;
  91 +
  92 + await _appReviewPromptLogic.maybeShowPrompt(context);
  93 + }
  94 +
  95 + Future<bool> _hasReviewPromptClickEvent() async {
  96 + if (!Get.isRegistered<ClickEventApi>()) return false;
  97 +
  98 + final result = await Get.find<ClickEventApi>().getClickEvent();
  99 + return switch (result) {
  100 + AppSuccess(:final data) =>
  101 + data.list?.any(
  102 + (item) =>
  103 + EventConst.keys.contains(item.eventName) &&
  104 + (item.clickCnt ?? 0) > 0,
  105 + ) ??
  106 + false,
  107 + AppFailure() => false,
  108 + };
86 } 109 }
87 110
88 Future<bool> maybeShowMembershipOffer() async { 111 Future<bool> maybeShowMembershipOffer() async {
@@ -102,7 +125,10 @@ class HomeController extends GetxController { @@ -102,7 +125,10 @@ class HomeController extends GetxController {
102 ); 125 );
103 await Get.toNamed( 126 await Get.toNamed(
104 Routes.PURCHASE, 127 Routes.PURCHASE,
105 - arguments: {PurchaseRouteArgs.showCloseButton: true}, 128 + arguments: {
  129 + PurchaseRouteArgs.showCloseButton: true,
  130 + IntentKeys.channelType: "登录全屏推送",
  131 + },
106 ); 132 );
107 return true; 133 return true;
108 } 134 }
@@ -120,7 +146,7 @@ class HomeController extends GetxController { @@ -120,7 +146,7 @@ class HomeController extends GetxController {
120 } else if (previousIndex == friendsTabIndex && index != friendsTabIndex) { 146 } else if (previousIndex == friendsTabIndex && index != friendsTabIndex) {
121 Get.find<FriendsController>().markPageHidden(); 147 Get.find<FriendsController>().markPageHidden();
122 } 148 }
123 - switch (index) { 149 + switch (index) {
124 case 0: 150 case 0:
125 Get.find<TodayController>().refreshTab(); 151 Get.find<TodayController>().refreshTab();
126 break; 152 break;
@@ -149,6 +175,7 @@ class HomeController extends GetxController { @@ -149,6 +175,7 @@ class HomeController extends GetxController {
149 final params = uri.queryParameters; // {"tab": "today"} 等 175 final params = uri.queryParameters; // {"tab": "today"} 等
150 176
151 _dispatchRoute(path, params); 177 _dispatchRoute(path, params);
  178 + _executePostClickEvent(path, params);
152 } catch (_) {} 179 } catch (_) {}
153 } 180 }
154 181
@@ -199,6 +226,24 @@ class HomeController extends GetxController { @@ -199,6 +226,24 @@ class HomeController extends GetxController {
199 } 226 }
200 } 227 }
201 228
  229 + void _executePostClickEvent(String path, Map<String, String> params) {
  230 + try {
  231 + var isHrvChange = params['is_hrv_change'] == "1";
  232 + if (isHrvChange) {
  233 + final clickEventApi = Get.find<ClickEventApi>();
  234 + if (!Get.isRegistered<ClickEventApi>()) return;
  235 + switch (path) {
  236 + case AppRoutes.home:
  237 + clickEventApi.postClickEvent(EventConst.hrvChangeClick);
  238 + break;
  239 + case Routes.FRIEND_HOME:
  240 + clickEventApi.postClickEvent(EventConst.friendHrvChangeClick);
  241 + break;
  242 + }
  243 + }
  244 + } catch (e) {}
  245 + }
  246 +
202 /// 根据 tab 名称切换首页底部 tab 247 /// 根据 tab 名称切换首页底部 tab
203 void _switchHomeTab(String? tab, Map<String, String> params) { 248 void _switchHomeTab(String? tab, Map<String, String> params) {
204 switch (tab) { 249 switch (tab) {
  1 +import 'package:doublefeel_flutter/core/constants/event_const.dart';
1 import 'package:flutter/material.dart'; 2 import 'package:flutter/material.dart';
2 import 'package:get/get.dart'; 3 import 'package:get/get.dart';
3 4
  5 +import '../../../../../core/network/api/click_event_api.dart';
4 import '../../../../../core/network/api/friend_api.dart'; 6 import '../../../../../core/network/api/friend_api.dart';
5 import '../../../../../core/result/app_result.dart'; 7 import '../../../../../core/result/app_result.dart';
6 import '../../../../../data/models/friend/friend_models.dart'; 8 import '../../../../../data/models/friend/friend_models.dart';
@@ -78,6 +80,7 @@ class TrendController extends GetxController with HealthTrendControl { @@ -78,6 +80,7 @@ class TrendController extends GetxController with HealthTrendControl {
78 if (userId == targetUserId.value) return; 80 if (userId == targetUserId.value) return;
79 targetUserId.value = userId; 81 targetUserId.value = userId;
80 refreshToken.value++; 82 refreshToken.value++;
  83 + _trackViewSleepStatsIfNeeded();
81 } 84 }
82 85
83 void selectFriend(FriendItem friendInfo) { 86 void selectFriend(FriendItem friendInfo) {
@@ -154,5 +157,19 @@ class TrendController extends GetxController with HealthTrendControl { @@ -154,5 +157,19 @@ class TrendController extends GetxController with HealthTrendControl {
154 selectedTypeIndex.value, 157 selectedTypeIndex.value,
155 userRole: targetFriendInfo.value == null ? '我的' : '好友的', 158 userRole: targetFriendInfo.value == null ? '我的' : '好友的',
156 ); 159 );
  160 + _trackViewSleepStatsIfNeeded();
  161 + }
  162 +
  163 + void _trackViewSleepStatsIfNeeded() {
  164 + if (!_isPageVisible ||
  165 + selectedTypeIndex.value != TrendType.sleep.tabIndex) {
  166 + return;
  167 + }
  168 +
  169 + final eventName = targetUserId.value == null
  170 + ? EventConst.viewSleepStats
  171 + : EventConst.viewFriendSleepStats;
  172 + if (!Get.isRegistered<ClickEventApi>()) return;
  173 + Get.find<ClickEventApi>().postClickEvent(eventName);
157 } 174 }
158 } 175 }
@@ -96,7 +96,11 @@ class PurchaseController extends GetxController { @@ -96,7 +96,11 @@ class PurchaseController extends GetxController {
96 arguments: {'from': 'onboarding'}, 96 arguments: {'from': 'onboarding'},
97 ); 97 );
98 } else { 98 } else {
99 - Get.back(); 99 + if (Navigator.canPop(Get.context!)) {
  100 + Get.back();
  101 + } else {
  102 + Get.offAllNamed(AppRoutes.home);
  103 + }
100 } 104 }
101 } 105 }
102 106
  1 +abstract final class EventConst {
  2 + static const String hrvChangeClick = "hrv_change_click";
  3 + static const String friendHrvChangeClick = "friend_hrv_change_click";
  4 + static const String viewSleepStats = "view_sleep_stats";
  5 + static const String viewFriendSleepStats = "view_friend_sleep_stats";
  6 +
  7 + static const Set<String> keys = {
  8 + hrvChangeClick,
  9 + friendHrvChangeClick,
  10 + viewSleepStats,
  11 + viewFriendSleepStats,
  12 + };
  13 +}
  1 +import 'package:doublefeel_flutter/data/models/event/click_event_data.dart';
  2 +
  3 +import '../../result/app_result.dart';
  4 +import '../../result/safe_call.dart';
  5 +import '../api_paths.dart';
  6 +import '../dio_client.dart';
  7 +
  8 +class ClickEventApi {
  9 + ClickEventApi(this._dioClient);
  10 +
  11 + final DioClient _dioClient;
  12 +
  13 + Future<AppResult<void>> postClickEvent(String eventName) {
  14 + return safeCall(
  15 + call: () async {
  16 + await _dioClient.dio.post(
  17 + ApiPaths.clickEvent,
  18 + data: {'event_name': eventName},
  19 + );
  20 + },
  21 + );
  22 + }
  23 +
  24 + Future<AppResult<ClickEventData>> getClickEvent() {
  25 + return safeCall(
  26 + call: () async {
  27 + final response = await _dioClient.dio.get(ApiPaths.clickEvent);
  28 + return ClickEventData.fromJson(response.data as Map<String, dynamic>);
  29 + },
  30 + errorHandlingPolicy: null,
  31 + );
  32 + }
  33 +}
@@ -72,4 +72,7 @@ abstract final class ApiPaths { @@ -72,4 +72,7 @@ abstract final class ApiPaths {
72 // friends 72 // friends
73 static const friends = '/client/doublefeel/health/v2/friends/'; 73 static const friends = '/client/doublefeel/health/v2/friends/';
74 static const friendInfo = '/client/doublefeel/health/v2/friend_info/'; 74 static const friendInfo = '/client/doublefeel/health/v2/friend_info/';
  75 +
  76 + // click event
  77 + static const clickEvent = '/client/doublefeel/click_event/';
75 } 78 }
  1 +class ClickEventData {
  2 + ClickEventData({
  3 + this.list,
  4 + });
  5 +
  6 + ClickEventData.fromJson(dynamic json) {
  7 + if (json['list'] != null) {
  8 + list = [];
  9 + json['list'].forEach((v) {
  10 + list?.add(ClickEventItem.fromJson(v));
  11 + });
  12 + }
  13 + }
  14 +
  15 + List<ClickEventItem>? list;
  16 +
  17 + Map<String, dynamic> toJson() {
  18 + final map = <String, dynamic>{};
  19 + if (list != null) {
  20 + map['list'] = list?.map((v) => v.toJson()).toList();
  21 + }
  22 + return map;
  23 + }
  24 +}
  25 +
  26 +class ClickEventItem {
  27 + ClickEventItem({
  28 + this.eventName,
  29 + this.clickCnt,
  30 + });
  31 +
  32 + ClickEventItem.fromJson(dynamic json) {
  33 + eventName = json['event_name'];
  34 + clickCnt = json['click_cnt'];
  35 + }
  36 +
  37 + String? eventName;
  38 + num? clickCnt;
  39 +
  40 + Map<String, dynamic> toJson() {
  41 + final map = <String, dynamic>{};
  42 + map['event_name'] = eventName;
  43 + map['click_cnt'] = clickCnt;
  44 + return map;
  45 + }
  46 +}
@@ -498,7 +498,8 @@ @@ -498,7 +498,8 @@
498 "refundFaqTitle": "DoubleFeel FAQs", 498 "refundFaqTitle": "DoubleFeel FAQs",
499 "appReviewPromptTitle": "Enjoying DoubleFeel?", 499 "appReviewPromptTitle": "Enjoying DoubleFeel?",
500 "appReviewPromptMessage": "Hi! Is DoubleFeel helping you better understand\nyour stress and sleep? 💜", 500 "appReviewPromptMessage": "Hi! Is DoubleFeel helping you better understand\nyour stress and sleep? 💜",
501 - "appReviewPromptLikeAction": "😍 Love it", 501 + "appReviewPromptLikeActionEmoji": "😍",
  502 + "appReviewPromptLikeAction": "Love it",
502 "appReviewPromptFeedbackAction": "I have feedback", 503 "appReviewPromptFeedbackAction": "I have feedback",
503 "appReviewFeedbackTitle": "We're sorry DoubleFeel didn't give you\na good experience", 504 "appReviewFeedbackTitle": "We're sorry DoubleFeel didn't give you\na good experience",
504 "appReviewFeedbackMessage": "Would you tell us what went wrong?\nYour feedback helps us improve the stress and health experience. 💜", 505 "appReviewFeedbackMessage": "Would you tell us what went wrong?\nYour feedback helps us improve the stress and health experience. 💜",
@@ -786,7 +786,8 @@ @@ -786,7 +786,8 @@
786 "refundFaqTitle": "DoubleFeel 常见问题", 786 "refundFaqTitle": "DoubleFeel 常见问题",
787 "appReviewPromptTitle": "喜欢 DoubleFeel 吗?", 787 "appReviewPromptTitle": "喜欢 DoubleFeel 吗?",
788 "appReviewPromptMessage": "嗨~想知道 DoubleFeel 是否正在帮助你\n更了解自己的压力与睡眠状态 💜", 788 "appReviewPromptMessage": "嗨~想知道 DoubleFeel 是否正在帮助你\n更了解自己的压力与睡眠状态 💜",
789 - "appReviewPromptLikeAction": "😍 很喜欢", 789 + "appReviewPromptLikeActionEmoji": "😍",
  790 + "appReviewPromptLikeAction": "很喜欢",
790 "appReviewPromptFeedbackAction": "我有意见", 791 "appReviewPromptFeedbackAction": "我有意见",
791 "appReviewFeedbackTitle": "很抱歉 DoubleFeel 没有带\n给你好的体验", 792 "appReviewFeedbackTitle": "很抱歉 DoubleFeel 没有带\n给你好的体验",
792 "appReviewFeedbackMessage": "愿意告诉我们遇到了什么问题吗?\n你的反馈可以帮助我们持续改进压力与健康体验 💜", 793 "appReviewFeedbackMessage": "愿意告诉我们遇到了什么问题吗?\n你的反馈可以帮助我们持续改进压力与健康体验 💜",
@@ -3087,10 +3087,16 @@ abstract class AppLocalizations { @@ -3087,10 +3087,16 @@ abstract class AppLocalizations {
3087 /// **'嗨~想知道 DoubleFeel 是否正在帮助你\n更了解自己的压力与睡眠状态 💜'** 3087 /// **'嗨~想知道 DoubleFeel 是否正在帮助你\n更了解自己的压力与睡眠状态 💜'**
3088 String get appReviewPromptMessage; 3088 String get appReviewPromptMessage;
3089 3089
  3090 + /// No description provided for @appReviewPromptLikeActionEmoji.
  3091 + ///
  3092 + /// In zh, this message translates to:
  3093 + /// **'😍'**
  3094 + String get appReviewPromptLikeActionEmoji;
  3095 +
3090 /// No description provided for @appReviewPromptLikeAction. 3096 /// No description provided for @appReviewPromptLikeAction.
3091 /// 3097 ///
3092 /// In zh, this message translates to: 3098 /// In zh, this message translates to:
3093 - /// **'😍 很喜欢'** 3099 + /// **'很喜欢'**
3094 String get appReviewPromptLikeAction; 3100 String get appReviewPromptLikeAction;
3095 3101
3096 /// No description provided for @appReviewPromptFeedbackAction. 3102 /// No description provided for @appReviewPromptFeedbackAction.
@@ -1722,7 +1722,10 @@ class AppLocalizationsEn extends AppLocalizations { @@ -1722,7 +1722,10 @@ class AppLocalizationsEn extends AppLocalizations {
1722 'Hi! Is DoubleFeel helping you better understand\nyour stress and sleep? 💜'; 1722 'Hi! Is DoubleFeel helping you better understand\nyour stress and sleep? 💜';
1723 1723
1724 @override 1724 @override
1725 - String get appReviewPromptLikeAction => '😍 Love it'; 1725 + String get appReviewPromptLikeActionEmoji => '😍';
  1726 +
  1727 + @override
  1728 + String get appReviewPromptLikeAction => 'Love it';
1726 1729
1727 @override 1730 @override
1728 String get appReviewPromptFeedbackAction => 'I have feedback'; 1731 String get appReviewPromptFeedbackAction => 'I have feedback';
@@ -1628,7 +1628,10 @@ class AppLocalizationsZh extends AppLocalizations { @@ -1628,7 +1628,10 @@ class AppLocalizationsZh extends AppLocalizations {
1628 '嗨~想知道 DoubleFeel 是否正在帮助你\n更了解自己的压力与睡眠状态 💜'; 1628 '嗨~想知道 DoubleFeel 是否正在帮助你\n更了解自己的压力与睡眠状态 💜';
1629 1629
1630 @override 1630 @override
1631 - String get appReviewPromptLikeAction => '😍 很喜欢'; 1631 + String get appReviewPromptLikeActionEmoji => '😍';
  1632 +
  1633 + @override
  1634 + String get appReviewPromptLikeAction => '很喜欢';
1632 1635
1633 @override 1636 @override
1634 String get appReviewPromptFeedbackAction => '我有意见'; 1637 String get appReviewPromptFeedbackAction => '我有意见';