diff --git a/lib/domain/record/components/notification_bar/components/recommend_premium_plan_in_trial.dart b/lib/domain/record/components/notification_bar/components/recommend_premium_plan_in_trial.dart new file mode 100644 index 0000000000..3dd9bf32cb --- /dev/null +++ b/lib/domain/record/components/notification_bar/components/recommend_premium_plan_in_trial.dart @@ -0,0 +1,71 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:pilll/analytics.dart'; +import 'package:pilll/components/atoms/font.dart'; +import 'package:pilll/components/atoms/text_color.dart'; + +class RecommendPremiumPlainInTrialNotificationBar extends StatelessWidget { + final VoidCallback onClose; + final VoidCallback onTap; + const RecommendPremiumPlainInTrialNotificationBar({ + Key? key, + required this.onClose, + required this.onTap, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + final double _closeButtonIconWidth = 24; + + return GestureDetector( + onTap: () { + analytics.logEvent(name: "tapped_recommend_premium_plan_in_trial"); + onTap(); + }, + child: Stack( + children: [ + Positioned( + top: 8, + child: GestureDetector( + child: Icon( + Icons.close, + color: Colors.white, + size: _closeButtonIconWidth, + ), + onTap: () { + analytics.logEvent( + name: "closed_recommend_premium_plan_in_trial"); + onClose(); + }, + ), + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SizedBox(width: _closeButtonIconWidth), + Spacer(), + Padding( + padding: const EdgeInsets.only(top: 12, bottom: 12), + child: Text( + "\今だけ!プレミアムプランが最大48%OFF/", + style: TextColorStyle.white.merge(FontType.descriptionBold), + textAlign: TextAlign.center, + ), + ), + Spacer(), + Padding( + padding: const EdgeInsets.only(right: 8, left: 8), + child: SvgPicture.asset( + "images/arrow_right.svg", + color: Colors.white, + width: 16, + height: 16, + ), + ), + ], + ), + ], + ), + ); + } +} diff --git a/lib/domain/record/components/notification_bar/notification_bar.dart b/lib/domain/record/components/notification_bar/notification_bar.dart index 02727d4a11..4bbb2d8595 100644 --- a/lib/domain/record/components/notification_bar/notification_bar.dart +++ b/lib/domain/record/components/notification_bar/notification_bar.dart @@ -11,6 +11,7 @@ import 'package:pilll/domain/premium_trial/premium_trial_modal.dart'; import 'package:pilll/domain/record/components/notification_bar/components/announce_supported_multiple_pill_sheet.dart'; import 'package:pilll/domain/record/components/notification_bar/components/discount_price_deadline.dart'; import 'package:pilll/domain/record/components/notification_bar/components/ended_pill_sheet.dart'; +import 'package:pilll/domain/record/components/notification_bar/components/recommend_premium_plan_in_trial.dart'; import 'package:pilll/domain/record/components/notification_bar/notification_bar_store.dart'; import 'package:pilll/domain/record/components/notification_bar/components/premium_trial_guide.dart'; import 'package:pilll/domain/record/components/notification_bar/components/premium_trial_limit.dart'; @@ -20,6 +21,7 @@ import 'package:pilll/domain/record/components/notification_bar/components/rest_ import 'package:pilll/domain/record/record_page_state.dart'; import 'package:pilll/signin/signin_sheet.dart'; import 'package:pilll/signin/signin_sheet_state.dart'; +import 'package:pilll/util/datetime/day.dart'; import 'package:pilll/util/shared_preference/keys.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -45,6 +47,27 @@ class NotificationBar extends HookConsumerWidget { final state = ref.watch(notificationBarStateProvider(parameter)); final store = ref.watch(notificationBarStoreProvider(parameter).notifier); if (!state.isPremium) { + if (!state.recommendPremiumPlainInTrialIsAlreadyClose) { + if (state.isTrial) { + final beginTrialDate = state.beginTrialDate; + if (beginTrialDate != null) { + final difference = now().difference(beginTrialDate).inSeconds; + final days14 = Duration(days: 14).inSeconds; + final days14Plus2 = Duration(days: 14 + 2).inSeconds; + if (difference > days14 && difference < days14Plus2) { + return RecommendPremiumPlainInTrialNotificationBar( + onTap: () { + showPremiumIntroductionSheet(context); + }, + onClose: () { + store.closeRecommendedPremiumPlainInTrial(); + }, + ); + } + } + } + } + final premiumTrialLimit = state.premiumTrialLimit; if (premiumTrialLimit != null) { return PremiumTrialLimitNotificationBar( diff --git a/lib/domain/record/components/notification_bar/notification_bar_state.dart b/lib/domain/record/components/notification_bar/notification_bar_state.dart index 7010eacdbd..73172be157 100644 --- a/lib/domain/record/components/notification_bar/notification_bar_state.dart +++ b/lib/domain/record/components/notification_bar/notification_bar_state.dart @@ -15,8 +15,10 @@ class NotificationBarState with _$NotificationBarState { required bool isTrial, required bool isAlreadyShowAnnouncementSupportedMultilplePillSheet, required bool hasDiscountEntitlement, + required DateTime? beginTrialDate, required DateTime? trialDeadlineDate, required DateTime? discountEntitlementDeadlineDate, + required bool recommendPremiumPlainInTrialIsAlreadyClose, required bool recommendedSignupNotificationIsAlreadyShow, required bool premiumTrialGuideNotificationIsClosed, required bool isLinkedLoginProvider, diff --git a/lib/domain/record/components/notification_bar/notification_bar_state.freezed.dart b/lib/domain/record/components/notification_bar/notification_bar_state.freezed.dart index 787c6da9ed..832e423cfb 100644 --- a/lib/domain/record/components/notification_bar/notification_bar_state.freezed.dart +++ b/lib/domain/record/components/notification_bar/notification_bar_state.freezed.dart @@ -25,8 +25,10 @@ class _$NotificationBarStateTearOff { required bool isTrial, required bool isAlreadyShowAnnouncementSupportedMultilplePillSheet, required bool hasDiscountEntitlement, + required DateTime? beginTrialDate, required DateTime? trialDeadlineDate, required DateTime? discountEntitlementDeadlineDate, + required bool recommendPremiumPlainInTrialIsAlreadyClose, required bool recommendedSignupNotificationIsAlreadyShow, required bool premiumTrialGuideNotificationIsClosed, required bool isLinkedLoginProvider}) { @@ -38,8 +40,11 @@ class _$NotificationBarStateTearOff { isAlreadyShowAnnouncementSupportedMultilplePillSheet: isAlreadyShowAnnouncementSupportedMultilplePillSheet, hasDiscountEntitlement: hasDiscountEntitlement, + beginTrialDate: beginTrialDate, trialDeadlineDate: trialDeadlineDate, discountEntitlementDeadlineDate: discountEntitlementDeadlineDate, + recommendPremiumPlainInTrialIsAlreadyClose: + recommendPremiumPlainInTrialIsAlreadyClose, recommendedSignupNotificationIsAlreadyShow: recommendedSignupNotificationIsAlreadyShow, premiumTrialGuideNotificationIsClosed: @@ -62,9 +67,12 @@ mixin _$NotificationBarState { bool get isAlreadyShowAnnouncementSupportedMultilplePillSheet => throw _privateConstructorUsedError; bool get hasDiscountEntitlement => throw _privateConstructorUsedError; + DateTime? get beginTrialDate => throw _privateConstructorUsedError; DateTime? get trialDeadlineDate => throw _privateConstructorUsedError; DateTime? get discountEntitlementDeadlineDate => throw _privateConstructorUsedError; + bool get recommendPremiumPlainInTrialIsAlreadyClose => + throw _privateConstructorUsedError; bool get recommendedSignupNotificationIsAlreadyShow => throw _privateConstructorUsedError; bool get premiumTrialGuideNotificationIsClosed => @@ -88,8 +96,10 @@ abstract class $NotificationBarStateCopyWith<$Res> { bool isTrial, bool isAlreadyShowAnnouncementSupportedMultilplePillSheet, bool hasDiscountEntitlement, + DateTime? beginTrialDate, DateTime? trialDeadlineDate, DateTime? discountEntitlementDeadlineDate, + bool recommendPremiumPlainInTrialIsAlreadyClose, bool recommendedSignupNotificationIsAlreadyShow, bool premiumTrialGuideNotificationIsClosed, bool isLinkedLoginProvider}); @@ -114,8 +124,10 @@ class _$NotificationBarStateCopyWithImpl<$Res> Object? isTrial = freezed, Object? isAlreadyShowAnnouncementSupportedMultilplePillSheet = freezed, Object? hasDiscountEntitlement = freezed, + Object? beginTrialDate = freezed, Object? trialDeadlineDate = freezed, Object? discountEntitlementDeadlineDate = freezed, + Object? recommendPremiumPlainInTrialIsAlreadyClose = freezed, Object? recommendedSignupNotificationIsAlreadyShow = freezed, Object? premiumTrialGuideNotificationIsClosed = freezed, Object? isLinkedLoginProvider = freezed, @@ -146,6 +158,10 @@ class _$NotificationBarStateCopyWithImpl<$Res> ? _value.hasDiscountEntitlement : hasDiscountEntitlement // ignore: cast_nullable_to_non_nullable as bool, + beginTrialDate: beginTrialDate == freezed + ? _value.beginTrialDate + : beginTrialDate // ignore: cast_nullable_to_non_nullable + as DateTime?, trialDeadlineDate: trialDeadlineDate == freezed ? _value.trialDeadlineDate : trialDeadlineDate // ignore: cast_nullable_to_non_nullable @@ -155,6 +171,11 @@ class _$NotificationBarStateCopyWithImpl<$Res> ? _value.discountEntitlementDeadlineDate : discountEntitlementDeadlineDate // ignore: cast_nullable_to_non_nullable as DateTime?, + recommendPremiumPlainInTrialIsAlreadyClose: + recommendPremiumPlainInTrialIsAlreadyClose == freezed + ? _value.recommendPremiumPlainInTrialIsAlreadyClose + : recommendPremiumPlainInTrialIsAlreadyClose // ignore: cast_nullable_to_non_nullable + as bool, recommendedSignupNotificationIsAlreadyShow: recommendedSignupNotificationIsAlreadyShow == freezed ? _value.recommendedSignupNotificationIsAlreadyShow @@ -198,8 +219,10 @@ abstract class _$NotificationBarStateCopyWith<$Res> bool isTrial, bool isAlreadyShowAnnouncementSupportedMultilplePillSheet, bool hasDiscountEntitlement, + DateTime? beginTrialDate, DateTime? trialDeadlineDate, DateTime? discountEntitlementDeadlineDate, + bool recommendPremiumPlainInTrialIsAlreadyClose, bool recommendedSignupNotificationIsAlreadyShow, bool premiumTrialGuideNotificationIsClosed, bool isLinkedLoginProvider}); @@ -227,8 +250,10 @@ class __$NotificationBarStateCopyWithImpl<$Res> Object? isTrial = freezed, Object? isAlreadyShowAnnouncementSupportedMultilplePillSheet = freezed, Object? hasDiscountEntitlement = freezed, + Object? beginTrialDate = freezed, Object? trialDeadlineDate = freezed, Object? discountEntitlementDeadlineDate = freezed, + Object? recommendPremiumPlainInTrialIsAlreadyClose = freezed, Object? recommendedSignupNotificationIsAlreadyShow = freezed, Object? premiumTrialGuideNotificationIsClosed = freezed, Object? isLinkedLoginProvider = freezed, @@ -259,6 +284,10 @@ class __$NotificationBarStateCopyWithImpl<$Res> ? _value.hasDiscountEntitlement : hasDiscountEntitlement // ignore: cast_nullable_to_non_nullable as bool, + beginTrialDate: beginTrialDate == freezed + ? _value.beginTrialDate + : beginTrialDate // ignore: cast_nullable_to_non_nullable + as DateTime?, trialDeadlineDate: trialDeadlineDate == freezed ? _value.trialDeadlineDate : trialDeadlineDate // ignore: cast_nullable_to_non_nullable @@ -268,6 +297,11 @@ class __$NotificationBarStateCopyWithImpl<$Res> ? _value.discountEntitlementDeadlineDate : discountEntitlementDeadlineDate // ignore: cast_nullable_to_non_nullable as DateTime?, + recommendPremiumPlainInTrialIsAlreadyClose: + recommendPremiumPlainInTrialIsAlreadyClose == freezed + ? _value.recommendPremiumPlainInTrialIsAlreadyClose + : recommendPremiumPlainInTrialIsAlreadyClose // ignore: cast_nullable_to_non_nullable + as bool, recommendedSignupNotificationIsAlreadyShow: recommendedSignupNotificationIsAlreadyShow == freezed ? _value.recommendedSignupNotificationIsAlreadyShow @@ -296,8 +330,10 @@ class _$_NotificationBarState extends _NotificationBarState { required this.isTrial, required this.isAlreadyShowAnnouncementSupportedMultilplePillSheet, required this.hasDiscountEntitlement, + required this.beginTrialDate, required this.trialDeadlineDate, required this.discountEntitlementDeadlineDate, + required this.recommendPremiumPlainInTrialIsAlreadyClose, required this.recommendedSignupNotificationIsAlreadyShow, required this.premiumTrialGuideNotificationIsClosed, required this.isLinkedLoginProvider}) @@ -316,10 +352,14 @@ class _$_NotificationBarState extends _NotificationBarState { @override final bool hasDiscountEntitlement; @override + final DateTime? beginTrialDate; + @override final DateTime? trialDeadlineDate; @override final DateTime? discountEntitlementDeadlineDate; @override + final bool recommendPremiumPlainInTrialIsAlreadyClose; + @override final bool recommendedSignupNotificationIsAlreadyShow; @override final bool premiumTrialGuideNotificationIsClosed; @@ -328,7 +368,7 @@ class _$_NotificationBarState extends _NotificationBarState { @override String toString() { - return 'NotificationBarState(latestPillSheetGroup: $latestPillSheetGroup, totalCountOfActionForTakenPill: $totalCountOfActionForTakenPill, isPremium: $isPremium, isTrial: $isTrial, isAlreadyShowAnnouncementSupportedMultilplePillSheet: $isAlreadyShowAnnouncementSupportedMultilplePillSheet, hasDiscountEntitlement: $hasDiscountEntitlement, trialDeadlineDate: $trialDeadlineDate, discountEntitlementDeadlineDate: $discountEntitlementDeadlineDate, recommendedSignupNotificationIsAlreadyShow: $recommendedSignupNotificationIsAlreadyShow, premiumTrialGuideNotificationIsClosed: $premiumTrialGuideNotificationIsClosed, isLinkedLoginProvider: $isLinkedLoginProvider)'; + return 'NotificationBarState(latestPillSheetGroup: $latestPillSheetGroup, totalCountOfActionForTakenPill: $totalCountOfActionForTakenPill, isPremium: $isPremium, isTrial: $isTrial, isAlreadyShowAnnouncementSupportedMultilplePillSheet: $isAlreadyShowAnnouncementSupportedMultilplePillSheet, hasDiscountEntitlement: $hasDiscountEntitlement, beginTrialDate: $beginTrialDate, trialDeadlineDate: $trialDeadlineDate, discountEntitlementDeadlineDate: $discountEntitlementDeadlineDate, recommendPremiumPlainInTrialIsAlreadyClose: $recommendPremiumPlainInTrialIsAlreadyClose, recommendedSignupNotificationIsAlreadyShow: $recommendedSignupNotificationIsAlreadyShow, premiumTrialGuideNotificationIsClosed: $premiumTrialGuideNotificationIsClosed, isLinkedLoginProvider: $isLinkedLoginProvider)'; } @override @@ -348,11 +388,16 @@ class _$_NotificationBarState extends _NotificationBarState { isAlreadyShowAnnouncementSupportedMultilplePillSheet) && const DeepCollectionEquality() .equals(other.hasDiscountEntitlement, hasDiscountEntitlement) && + const DeepCollectionEquality() + .equals(other.beginTrialDate, beginTrialDate) && const DeepCollectionEquality() .equals(other.trialDeadlineDate, trialDeadlineDate) && const DeepCollectionEquality().equals( other.discountEntitlementDeadlineDate, discountEntitlementDeadlineDate) && + const DeepCollectionEquality().equals( + other.recommendPremiumPlainInTrialIsAlreadyClose, + recommendPremiumPlainInTrialIsAlreadyClose) && const DeepCollectionEquality().equals( other.recommendedSignupNotificationIsAlreadyShow, recommendedSignupNotificationIsAlreadyShow) && @@ -373,8 +418,11 @@ class _$_NotificationBarState extends _NotificationBarState { const DeepCollectionEquality() .hash(isAlreadyShowAnnouncementSupportedMultilplePillSheet), const DeepCollectionEquality().hash(hasDiscountEntitlement), + const DeepCollectionEquality().hash(beginTrialDate), const DeepCollectionEquality().hash(trialDeadlineDate), const DeepCollectionEquality().hash(discountEntitlementDeadlineDate), + const DeepCollectionEquality() + .hash(recommendPremiumPlainInTrialIsAlreadyClose), const DeepCollectionEquality() .hash(recommendedSignupNotificationIsAlreadyShow), const DeepCollectionEquality() @@ -396,8 +444,10 @@ abstract class _NotificationBarState extends NotificationBarState { required bool isTrial, required bool isAlreadyShowAnnouncementSupportedMultilplePillSheet, required bool hasDiscountEntitlement, + required DateTime? beginTrialDate, required DateTime? trialDeadlineDate, required DateTime? discountEntitlementDeadlineDate, + required bool recommendPremiumPlainInTrialIsAlreadyClose, required bool recommendedSignupNotificationIsAlreadyShow, required bool premiumTrialGuideNotificationIsClosed, required bool isLinkedLoginProvider}) = _$_NotificationBarState; @@ -416,10 +466,14 @@ abstract class _NotificationBarState extends NotificationBarState { @override bool get hasDiscountEntitlement; @override + DateTime? get beginTrialDate; + @override DateTime? get trialDeadlineDate; @override DateTime? get discountEntitlementDeadlineDate; @override + bool get recommendPremiumPlainInTrialIsAlreadyClose; + @override bool get recommendedSignupNotificationIsAlreadyShow; @override bool get premiumTrialGuideNotificationIsClosed; diff --git a/lib/domain/record/components/notification_bar/notification_bar_store.dart b/lib/domain/record/components/notification_bar/notification_bar_store.dart index b398001489..9481e1e17a 100644 --- a/lib/domain/record/components/notification_bar/notification_bar_store.dart +++ b/lib/domain/record/components/notification_bar/notification_bar_store.dart @@ -30,16 +30,26 @@ class NotificationBarStateStore extends StateNotifier { hasDiscountEntitlement: parameter.hasDiscountEntitlement, isAlreadyShowAnnouncementSupportedMultilplePillSheet: parameter.isAlreadyShowAnnouncementSupportedMultilplePillSheet, + beginTrialDate: parameter.beginTrialDate, trialDeadlineDate: parameter.trialDeadlineDate, discountEntitlementDeadlineDate: parameter.discountEntitlementDeadlineDate, isLinkedLoginProvider: parameter.isLinkedLoginProvider, + recommendPremiumPlainInTrialIsAlreadyClose: + parameter.recommendPremiumPlainInTrialIsAlreadyClose, premiumTrialGuideNotificationIsClosed: parameter.premiumTrialGuideNotificationIsClosed, recommendedSignupNotificationIsAlreadyShow: parameter.recommendedSignupNotificationIsAlreadyShow, ), ); + Future closeRecommendedPremiumPlainInTrial() async { + final sharedPreferences = await SharedPreferences.getInstance(); + sharedPreferences.setBool( + BoolKey.recommendPremiumPlainInTrialIsAlreadyClose, true); + state = state.copyWith(recommendPremiumPlainInTrialIsAlreadyClose: true); + } + Future closeRecommendedSignupNotification() async { final sharedPreferences = await SharedPreferences.getInstance(); sharedPreferences.setBool( diff --git a/lib/domain/record/record_page_state.dart b/lib/domain/record/record_page_state.dart index 9e2bfdf39f..2f4620d70e 100644 --- a/lib/domain/record/record_page_state.dart +++ b/lib/domain/record/record_page_state.dart @@ -23,6 +23,7 @@ class RecordPageState with _$RecordPageState { DateTime? beginTrialDate, DateTime? trialDeadlineDate, DateTime? discountEntitlementDeadlineDate, + @Default(false) bool recommendPremiumPlainInTrialIsAlreadyClose, @Default(true) bool recommendedSignupNotificationIsAlreadyShow, @Default(true) bool premiumTrialGuideNotificationIsClosed, Object? exception, diff --git a/lib/domain/record/record_page_state.freezed.dart b/lib/domain/record/record_page_state.freezed.dart index 581c82b211..1b47527726 100644 --- a/lib/domain/record/record_page_state.freezed.dart +++ b/lib/domain/record/record_page_state.freezed.dart @@ -34,6 +34,7 @@ class _$RecordPageStateTearOff { DateTime? beginTrialDate, DateTime? trialDeadlineDate, DateTime? discountEntitlementDeadlineDate, + bool recommendPremiumPlainInTrialIsAlreadyClose = false, bool recommendedSignupNotificationIsAlreadyShow = true, bool premiumTrialGuideNotificationIsClosed = true, Object? exception}) { @@ -54,6 +55,8 @@ class _$RecordPageStateTearOff { beginTrialDate: beginTrialDate, trialDeadlineDate: trialDeadlineDate, discountEntitlementDeadlineDate: discountEntitlementDeadlineDate, + recommendPremiumPlainInTrialIsAlreadyClose: + recommendPremiumPlainInTrialIsAlreadyClose, recommendedSignupNotificationIsAlreadyShow: recommendedSignupNotificationIsAlreadyShow, premiumTrialGuideNotificationIsClosed: @@ -85,6 +88,8 @@ mixin _$RecordPageState { DateTime? get trialDeadlineDate => throw _privateConstructorUsedError; DateTime? get discountEntitlementDeadlineDate => throw _privateConstructorUsedError; + bool get recommendPremiumPlainInTrialIsAlreadyClose => + throw _privateConstructorUsedError; bool get recommendedSignupNotificationIsAlreadyShow => throw _privateConstructorUsedError; bool get premiumTrialGuideNotificationIsClosed => @@ -117,6 +122,7 @@ abstract class $RecordPageStateCopyWith<$Res> { DateTime? beginTrialDate, DateTime? trialDeadlineDate, DateTime? discountEntitlementDeadlineDate, + bool recommendPremiumPlainInTrialIsAlreadyClose, bool recommendedSignupNotificationIsAlreadyShow, bool premiumTrialGuideNotificationIsClosed, Object? exception}); @@ -151,6 +157,7 @@ class _$RecordPageStateCopyWithImpl<$Res> Object? beginTrialDate = freezed, Object? trialDeadlineDate = freezed, Object? discountEntitlementDeadlineDate = freezed, + Object? recommendPremiumPlainInTrialIsAlreadyClose = freezed, Object? recommendedSignupNotificationIsAlreadyShow = freezed, Object? premiumTrialGuideNotificationIsClosed = freezed, Object? exception = freezed, @@ -218,6 +225,11 @@ class _$RecordPageStateCopyWithImpl<$Res> ? _value.discountEntitlementDeadlineDate : discountEntitlementDeadlineDate // ignore: cast_nullable_to_non_nullable as DateTime?, + recommendPremiumPlainInTrialIsAlreadyClose: + recommendPremiumPlainInTrialIsAlreadyClose == freezed + ? _value.recommendPremiumPlainInTrialIsAlreadyClose + : recommendPremiumPlainInTrialIsAlreadyClose // ignore: cast_nullable_to_non_nullable + as bool, recommendedSignupNotificationIsAlreadyShow: recommendedSignupNotificationIsAlreadyShow == freezed ? _value.recommendedSignupNotificationIsAlreadyShow @@ -278,6 +290,7 @@ abstract class _$RecordPageStateCopyWith<$Res> DateTime? beginTrialDate, DateTime? trialDeadlineDate, DateTime? discountEntitlementDeadlineDate, + bool recommendPremiumPlainInTrialIsAlreadyClose, bool recommendedSignupNotificationIsAlreadyShow, bool premiumTrialGuideNotificationIsClosed, Object? exception}); @@ -316,6 +329,7 @@ class __$RecordPageStateCopyWithImpl<$Res> Object? beginTrialDate = freezed, Object? trialDeadlineDate = freezed, Object? discountEntitlementDeadlineDate = freezed, + Object? recommendPremiumPlainInTrialIsAlreadyClose = freezed, Object? recommendedSignupNotificationIsAlreadyShow = freezed, Object? premiumTrialGuideNotificationIsClosed = freezed, Object? exception = freezed, @@ -383,6 +397,11 @@ class __$RecordPageStateCopyWithImpl<$Res> ? _value.discountEntitlementDeadlineDate : discountEntitlementDeadlineDate // ignore: cast_nullable_to_non_nullable as DateTime?, + recommendPremiumPlainInTrialIsAlreadyClose: + recommendPremiumPlainInTrialIsAlreadyClose == freezed + ? _value.recommendPremiumPlainInTrialIsAlreadyClose + : recommendPremiumPlainInTrialIsAlreadyClose // ignore: cast_nullable_to_non_nullable + as bool, recommendedSignupNotificationIsAlreadyShow: recommendedSignupNotificationIsAlreadyShow == freezed ? _value.recommendedSignupNotificationIsAlreadyShow @@ -417,6 +436,7 @@ class _$_RecordPageState extends _RecordPageState { this.beginTrialDate, this.trialDeadlineDate, this.discountEntitlementDeadlineDate, + this.recommendPremiumPlainInTrialIsAlreadyClose = false, this.recommendedSignupNotificationIsAlreadyShow = true, this.premiumTrialGuideNotificationIsClosed = true, this.exception}) @@ -464,6 +484,9 @@ class _$_RecordPageState extends _RecordPageState { final DateTime? discountEntitlementDeadlineDate; @JsonKey() @override + final bool recommendPremiumPlainInTrialIsAlreadyClose; + @JsonKey() + @override final bool recommendedSignupNotificationIsAlreadyShow; @JsonKey() @override @@ -473,7 +496,7 @@ class _$_RecordPageState extends _RecordPageState { @override String toString() { - return 'RecordPageState(pillSheetGroup: $pillSheetGroup, setting: $setting, totalCountOfActionForTakenPill: $totalCountOfActionForTakenPill, firstLoadIsEnded: $firstLoadIsEnded, isPremium: $isPremium, isTrial: $isTrial, hasDiscountEntitlement: $hasDiscountEntitlement, isAlreadyShowAnnouncementSupportedMultilplePillSheet: $isAlreadyShowAnnouncementSupportedMultilplePillSheet, isAlreadyShowTiral: $isAlreadyShowTiral, isAlreadyShowPremiumSurvey: $isAlreadyShowPremiumSurvey, shouldShowMigrateInfo: $shouldShowMigrateInfo, isLinkedLoginProvider: $isLinkedLoginProvider, beginTrialDate: $beginTrialDate, trialDeadlineDate: $trialDeadlineDate, discountEntitlementDeadlineDate: $discountEntitlementDeadlineDate, recommendedSignupNotificationIsAlreadyShow: $recommendedSignupNotificationIsAlreadyShow, premiumTrialGuideNotificationIsClosed: $premiumTrialGuideNotificationIsClosed, exception: $exception)'; + return 'RecordPageState(pillSheetGroup: $pillSheetGroup, setting: $setting, totalCountOfActionForTakenPill: $totalCountOfActionForTakenPill, firstLoadIsEnded: $firstLoadIsEnded, isPremium: $isPremium, isTrial: $isTrial, hasDiscountEntitlement: $hasDiscountEntitlement, isAlreadyShowAnnouncementSupportedMultilplePillSheet: $isAlreadyShowAnnouncementSupportedMultilplePillSheet, isAlreadyShowTiral: $isAlreadyShowTiral, isAlreadyShowPremiumSurvey: $isAlreadyShowPremiumSurvey, shouldShowMigrateInfo: $shouldShowMigrateInfo, isLinkedLoginProvider: $isLinkedLoginProvider, beginTrialDate: $beginTrialDate, trialDeadlineDate: $trialDeadlineDate, discountEntitlementDeadlineDate: $discountEntitlementDeadlineDate, recommendPremiumPlainInTrialIsAlreadyClose: $recommendPremiumPlainInTrialIsAlreadyClose, recommendedSignupNotificationIsAlreadyShow: $recommendedSignupNotificationIsAlreadyShow, premiumTrialGuideNotificationIsClosed: $premiumTrialGuideNotificationIsClosed, exception: $exception)'; } @override @@ -511,6 +534,9 @@ class _$_RecordPageState extends _RecordPageState { const DeepCollectionEquality().equals( other.discountEntitlementDeadlineDate, discountEntitlementDeadlineDate) && + const DeepCollectionEquality().equals( + other.recommendPremiumPlainInTrialIsAlreadyClose, + recommendPremiumPlainInTrialIsAlreadyClose) && const DeepCollectionEquality().equals( other.recommendedSignupNotificationIsAlreadyShow, recommendedSignupNotificationIsAlreadyShow) && @@ -521,29 +547,32 @@ class _$_RecordPageState extends _RecordPageState { } @override - int get hashCode => Object.hash( - runtimeType, - const DeepCollectionEquality().hash(pillSheetGroup), - const DeepCollectionEquality().hash(setting), - const DeepCollectionEquality().hash(totalCountOfActionForTakenPill), - const DeepCollectionEquality().hash(firstLoadIsEnded), - const DeepCollectionEquality().hash(isPremium), - const DeepCollectionEquality().hash(isTrial), - const DeepCollectionEquality().hash(hasDiscountEntitlement), - const DeepCollectionEquality() - .hash(isAlreadyShowAnnouncementSupportedMultilplePillSheet), - const DeepCollectionEquality().hash(isAlreadyShowTiral), - const DeepCollectionEquality().hash(isAlreadyShowPremiumSurvey), - const DeepCollectionEquality().hash(shouldShowMigrateInfo), - const DeepCollectionEquality().hash(isLinkedLoginProvider), - const DeepCollectionEquality().hash(beginTrialDate), - const DeepCollectionEquality().hash(trialDeadlineDate), - const DeepCollectionEquality().hash(discountEntitlementDeadlineDate), - const DeepCollectionEquality() - .hash(recommendedSignupNotificationIsAlreadyShow), - const DeepCollectionEquality() - .hash(premiumTrialGuideNotificationIsClosed), - const DeepCollectionEquality().hash(exception)); + int get hashCode => Object.hashAll([ + runtimeType, + const DeepCollectionEquality().hash(pillSheetGroup), + const DeepCollectionEquality().hash(setting), + const DeepCollectionEquality().hash(totalCountOfActionForTakenPill), + const DeepCollectionEquality().hash(firstLoadIsEnded), + const DeepCollectionEquality().hash(isPremium), + const DeepCollectionEquality().hash(isTrial), + const DeepCollectionEquality().hash(hasDiscountEntitlement), + const DeepCollectionEquality() + .hash(isAlreadyShowAnnouncementSupportedMultilplePillSheet), + const DeepCollectionEquality().hash(isAlreadyShowTiral), + const DeepCollectionEquality().hash(isAlreadyShowPremiumSurvey), + const DeepCollectionEquality().hash(shouldShowMigrateInfo), + const DeepCollectionEquality().hash(isLinkedLoginProvider), + const DeepCollectionEquality().hash(beginTrialDate), + const DeepCollectionEquality().hash(trialDeadlineDate), + const DeepCollectionEquality().hash(discountEntitlementDeadlineDate), + const DeepCollectionEquality() + .hash(recommendPremiumPlainInTrialIsAlreadyClose), + const DeepCollectionEquality() + .hash(recommendedSignupNotificationIsAlreadyShow), + const DeepCollectionEquality() + .hash(premiumTrialGuideNotificationIsClosed), + const DeepCollectionEquality().hash(exception) + ]); @JsonKey(ignore: true) @override @@ -568,6 +597,7 @@ abstract class _RecordPageState extends RecordPageState { DateTime? beginTrialDate, DateTime? trialDeadlineDate, DateTime? discountEntitlementDeadlineDate, + bool recommendPremiumPlainInTrialIsAlreadyClose, bool recommendedSignupNotificationIsAlreadyShow, bool premiumTrialGuideNotificationIsClosed, Object? exception}) = _$_RecordPageState; @@ -604,6 +634,8 @@ abstract class _RecordPageState extends RecordPageState { @override DateTime? get discountEntitlementDeadlineDate; @override + bool get recommendPremiumPlainInTrialIsAlreadyClose; + @override bool get recommendedSignupNotificationIsAlreadyShow; @override bool get premiumTrialGuideNotificationIsClosed; diff --git a/lib/domain/record/record_page_store.dart b/lib/domain/record/record_page_store.dart index eba422414e..b2a103e66d 100644 --- a/lib/domain/record/record_page_store.dart +++ b/lib/domain/record/record_page_store.dart @@ -73,6 +73,7 @@ class RecordPageStore extends StateNotifier { hasDiscountEntitlement: user.hasDiscountEntitlement, discountEntitlementDeadlineDate: user.discountEntitlementDeadlineDate, + beginTrialDate: user.beginTrialDate, trialDeadlineDate: user.trialDeadlineDate, ); }), @@ -99,6 +100,10 @@ class RecordPageStore extends StateNotifier { } return true; }(); + final recommendPremiumPlainInTrialIsAlreadyClose = + sharedPreferences.getBool( + BoolKey.recommendPremiumPlainInTrialIsAlreadyClose) ?? + false; final recommendedSignupNotificationIsAlreadyShow = sharedPreferences.getBool( BoolKey.recommendedSignupNotificationIsAlreadyShow) ?? @@ -119,6 +124,8 @@ class RecordPageStore extends StateNotifier { sharedPreferences.getBool(BoolKey .isAlreadyShowAnnouncementSupportedMultilplePillSheet) ?? false, + recommendPremiumPlainInTrialIsAlreadyClose: + recommendPremiumPlainInTrialIsAlreadyClose, recommendedSignupNotificationIsAlreadyShow: recommendedSignupNotificationIsAlreadyShow, premiumTrialGuideNotificationIsClosed: @@ -161,6 +168,7 @@ class RecordPageStore extends StateNotifier { isPremium: event.isPremium, isTrial: event.isTrial, hasDiscountEntitlement: event.hasDiscountEntitlement, + beginTrialDate: event.beginTrialDate, trialDeadlineDate: event.trialDeadlineDate, discountEntitlementDeadlineDate: event.discountEntitlementDeadlineDate, ); diff --git a/lib/util/shared_preference/keys.dart b/lib/util/shared_preference/keys.dart index bfbc29191a..0bb9ecaee4 100644 --- a/lib/util/shared_preference/keys.dart +++ b/lib/util/shared_preference/keys.dart @@ -2,6 +2,8 @@ extension BoolKey on String { static final didEndInitialSetting = "isDidEndInitialSettingKey"; static final recommendedSignupNotificationIsAlreadyShow = "recommendedSignupNotificationIsAlreadyShow"; + static final recommendPremiumPlainInTrialIsAlreadyClose = + "recommendPremiumPlainInTrialIsAlreadyClose"; static final premiumTrialGuideNotificationIsClosed = "premiumTrialGuideNotificationIsClosed"; static final isAlreadyShowAnnouncementSupportedMultilplePillSheet = diff --git a/test/domain/record/notification_bar/notification_bar_test.dart b/test/domain/record/notification_bar/notification_bar_test.dart index 765358a78d..6d37aa0431 100644 --- a/test/domain/record/notification_bar/notification_bar_test.dart +++ b/test/domain/record/notification_bar/notification_bar_test.dart @@ -3,6 +3,7 @@ import 'package:pilll/domain/premium_introduction/util/discount_deadline.dart'; import 'package:pilll/domain/record/components/notification_bar/components/announce_supported_multiple_pill_sheet.dart'; import 'package:pilll/domain/record/components/notification_bar/components/discount_price_deadline.dart'; import 'package:pilll/domain/record/components/notification_bar/components/ended_pill_sheet.dart'; +import 'package:pilll/domain/record/components/notification_bar/components/recommend_premium_plan_in_trial.dart'; import 'package:pilll/domain/record/components/notification_bar/notification_bar.dart'; import 'package:pilll/domain/record/components/notification_bar/notification_bar_state.dart'; import 'package:pilll/domain/record/components/notification_bar/notification_bar_store.dart'; @@ -44,6 +45,73 @@ void main() { }); group('notification bar appearance content type', () { group('for it is not premium user', () { + testWidgets('#RecommendPremiumPlainInTrialNotificationBar', + (WidgetTester tester) async { + final mockTodayRepository = MockTodayService(); + final today = DateTime(2021, 04, 29); + + when(mockTodayRepository.today()).thenReturn(today); + when(mockTodayRepository.now()).thenReturn(today); + todayRepository = mockTodayRepository; + + var pillSheet = PillSheet.create(PillSheetType.pillsheet_21); + pillSheet = pillSheet.copyWith( + lastTakenDate: today, + beginingDate: today.subtract( +// NOTE: Into rest duration and notification duration + Duration(days: 25), + ), + ); + final pillSheetGroup = PillSheetGroup( + pillSheetIDs: ["1"], pillSheets: [pillSheet], createdAt: now()); + final state = NotificationBarState( + latestPillSheetGroup: pillSheetGroup, + totalCountOfActionForTakenPill: + totalCountOfActionForTakenPillForLongTimeUser, + isPremium: false, + isTrial: true, + hasDiscountEntitlement: true, + isAlreadyShowAnnouncementSupportedMultilplePillSheet: false, + isLinkedLoginProvider: false, + premiumTrialGuideNotificationIsClosed: false, + recommendPremiumPlainInTrialIsAlreadyClose: false, + recommendedSignupNotificationIsAlreadyShow: false, + beginTrialDate: today.subtract(Duration(days: 15)), + trialDeadlineDate: null, + discountEntitlementDeadlineDate: today.subtract(Duration(days: 1)), + ); + + final recordPageState = RecordPageState( + pillSheetGroup: PillSheetGroup( + pillSheets: [pillSheet], + pillSheetIDs: ["1"], + createdAt: now())); + await tester.pumpWidget( + ProviderScope( + overrides: [ + notificationBarStoreProvider.overrideWithProvider((param) => + StateNotifierProvider.autoDispose( + (_) => MockNotificationBarStateStore())), + notificationBarStateProvider.overrideWithProvider( + (param) => Provider.autoDispose((_) => state)), + isOverDiscountDeadlineProvider.overrideWithProvider( + (param) => Provider.autoDispose((_) => false)), + durationToDiscountPriceDeadline.overrideWithProvider((param) => + Provider.autoDispose((_) => Duration(seconds: 1000))), + ], + child: MaterialApp( + home: Material(child: NotificationBar(recordPageState)), + ), + ), + ); + await tester.pump(); + + expect( + find.byWidgetPredicate((widget) => + widget is RecommendPremiumPlainInTrialNotificationBar), + findsOneWidget, + ); + }); testWidgets('#DiscountPriceDeadline', (WidgetTester tester) async { final mockTodayRepository = MockTodayService(); final today = DateTime(2021, 04, 29); @@ -72,7 +140,9 @@ void main() { isAlreadyShowAnnouncementSupportedMultilplePillSheet: false, isLinkedLoginProvider: false, premiumTrialGuideNotificationIsClosed: false, + recommendPremiumPlainInTrialIsAlreadyClose: false, recommendedSignupNotificationIsAlreadyShow: false, + beginTrialDate: null, trialDeadlineDate: null, discountEntitlementDeadlineDate: today.subtract(Duration(days: 1)), ); @@ -135,7 +205,9 @@ void main() { isAlreadyShowAnnouncementSupportedMultilplePillSheet: false, isLinkedLoginProvider: false, premiumTrialGuideNotificationIsClosed: false, + recommendPremiumPlainInTrialIsAlreadyClose: false, recommendedSignupNotificationIsAlreadyShow: false, + beginTrialDate: null, trialDeadlineDate: null, discountEntitlementDeadlineDate: null, ); @@ -197,7 +269,9 @@ void main() { isAlreadyShowAnnouncementSupportedMultilplePillSheet: false, isLinkedLoginProvider: false, premiumTrialGuideNotificationIsClosed: false, + recommendPremiumPlainInTrialIsAlreadyClose: false, recommendedSignupNotificationIsAlreadyShow: false, + beginTrialDate: null, trialDeadlineDate: null, discountEntitlementDeadlineDate: null, ); @@ -258,7 +332,9 @@ void main() { isAlreadyShowAnnouncementSupportedMultilplePillSheet: false, isLinkedLoginProvider: true, premiumTrialGuideNotificationIsClosed: false, + recommendPremiumPlainInTrialIsAlreadyClose: false, recommendedSignupNotificationIsAlreadyShow: false, + beginTrialDate: null, trialDeadlineDate: null, discountEntitlementDeadlineDate: null, ); @@ -320,7 +396,9 @@ void main() { isAlreadyShowAnnouncementSupportedMultilplePillSheet: false, isLinkedLoginProvider: true, premiumTrialGuideNotificationIsClosed: false, + recommendPremiumPlainInTrialIsAlreadyClose: false, recommendedSignupNotificationIsAlreadyShow: false, + beginTrialDate: null, trialDeadlineDate: today.add(Duration(days: 1)), discountEntitlementDeadlineDate: null, ); @@ -381,7 +459,9 @@ void main() { isAlreadyShowAnnouncementSupportedMultilplePillSheet: false, isLinkedLoginProvider: true, premiumTrialGuideNotificationIsClosed: false, + recommendPremiumPlainInTrialIsAlreadyClose: false, recommendedSignupNotificationIsAlreadyShow: false, + beginTrialDate: null, trialDeadlineDate: null, discountEntitlementDeadlineDate: null, ); @@ -444,7 +524,9 @@ void main() { isAlreadyShowAnnouncementSupportedMultilplePillSheet: false, isLinkedLoginProvider: false, premiumTrialGuideNotificationIsClosed: false, + recommendPremiumPlainInTrialIsAlreadyClose: false, recommendedSignupNotificationIsAlreadyShow: false, + beginTrialDate: null, trialDeadlineDate: null, discountEntitlementDeadlineDate: null, ); @@ -505,7 +587,9 @@ void main() { isAlreadyShowAnnouncementSupportedMultilplePillSheet: false, isLinkedLoginProvider: true, premiumTrialGuideNotificationIsClosed: false, + recommendPremiumPlainInTrialIsAlreadyClose: false, recommendedSignupNotificationIsAlreadyShow: false, + beginTrialDate: null, trialDeadlineDate: null, discountEntitlementDeadlineDate: null, ); @@ -566,7 +650,9 @@ void main() { isAlreadyShowAnnouncementSupportedMultilplePillSheet: false, isLinkedLoginProvider: true, premiumTrialGuideNotificationIsClosed: false, + recommendPremiumPlainInTrialIsAlreadyClose: false, recommendedSignupNotificationIsAlreadyShow: false, + beginTrialDate: null, trialDeadlineDate: null, discountEntitlementDeadlineDate: null, ); @@ -629,7 +715,9 @@ void main() { isAlreadyShowAnnouncementSupportedMultilplePillSheet: false, isLinkedLoginProvider: true, premiumTrialGuideNotificationIsClosed: false, + recommendPremiumPlainInTrialIsAlreadyClose: false, recommendedSignupNotificationIsAlreadyShow: false, + beginTrialDate: null, trialDeadlineDate: null, discountEntitlementDeadlineDate: null, ); diff --git a/test/helper/mock.mocks.dart b/test/helper/mock.mocks.dart index 0e89f2c8b7..0a9b9c5cb4 100644 --- a/test/helper/mock.mocks.dart +++ b/test/helper/mock.mocks.dart @@ -585,6 +585,12 @@ class MockNotificationBarStateStore extends _i1.Mock (super.noSuchMethod(Invocation.getter(#hasListeners), returnValue: false) as bool); @override + _i16.Future closeRecommendedPremiumPlainInTrial() => (super + .noSuchMethod(Invocation.method(#closeRecommendedPremiumPlainInTrial, []), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i16 + .Future); + @override _i16.Future closeRecommendedSignupNotification() => (super.noSuchMethod( Invocation.method(#closeRecommendedSignupNotification, []), returnValue: Future.value(),