diff --git a/images/explain_rest_duration.svg b/images/explain_rest_duration.svg new file mode 100644 index 0000000000..75fc242471 --- /dev/null +++ b/images/explain_rest_duration.svg @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/components/atoms/buttons.dart b/lib/components/atoms/buttons.dart index a4f7a1c0c2..c4fea27a35 100644 --- a/lib/components/atoms/buttons.dart +++ b/lib/components/atoms/buttons.dart @@ -99,25 +99,26 @@ class InconspicuousButton extends StatelessWidget { class PrimaryOutlinedButton extends StatelessWidget { final String text; + final double fontSize; final VoidCallback? onPressed; const PrimaryOutlinedButton({ Key? key, required this.onPressed, + required this.fontSize, required this.text, }) : super(key: key); Widget build(BuildContext context) { return OutlinedButton( child: Container( - width: 204, padding: EdgeInsets.only(top: 12, bottom: 12), child: Center( child: Text( text, style: TextStyle( color: TextColor.main, - fontSize: 16, + fontSize: fontSize, fontFamily: FontFamily.japanese, fontWeight: FontWeight.w700, ), diff --git a/lib/components/atoms/color.dart b/lib/components/atoms/color.dart index 98fec77982..920837ed47 100644 --- a/lib/components/atoms/color.dart +++ b/lib/components/atoms/color.dart @@ -30,7 +30,7 @@ class PilllColors { static final Color saturday = HexColor.fromHex("7FB9E1"); static final Color weekday = HexColor.fromHex("7E7E7E"); static final Color enable = HexColor.fromHex('E56A45'); - static final Color disable = HexColor.fromHex("F2F2F2"); + static final Color disable = HexColor.fromHex("EAEAEA"); static final Color divider = HexColor.fromHex("9DAFBD"); static final Color bottomBar = HexColor.fromHex("FAFAFA"); diff --git a/lib/components/atoms/text_color.dart b/lib/components/atoms/text_color.dart index b4de7f3309..0599385144 100644 --- a/lib/components/atoms/text_color.dart +++ b/lib/components/atoms/text_color.dart @@ -8,7 +8,7 @@ class TextColor { static final Color white = Colors.white; static final Color darkGray = HexColor.fromHex("000000").withAlpha(153); static final Color gray = HexColor.fromHex("7E7E7E"); - static final Color lightGray = HexColor.fromHex("CDCFD1"); + static final Color lightGray = HexColor.fromHex("B1B1B1"); static final Color lightGray2 = HexColor.fromHex("666666"); static final Color noshime = HexColor.fromHex("3D4662"); static final Color primary = PilllColors.primary; diff --git a/lib/components/organisms/calendar/utility.dart b/lib/components/organisms/calendar/utility.dart index 4933056d34..bb083dcdeb 100644 --- a/lib/components/organisms/calendar/utility.dart +++ b/lib/components/organisms/calendar/utility.dart @@ -23,17 +23,20 @@ List scheduledOrInTheMiddleMenstruationDateRanges( } assert(maxPageCount > 0); + final totalPillCount = pillSheetGroup.pillSheets + .map((e) => e.pillSheetType.totalCount) + .reduce((value, element) => value + element); final List dateRanges = []; // 大体の数を計算 for (int i = 0; i < maxPageCount; i++) { - final offset = pillSheetGroup.totalPillCountIntoGroup * i; + final offset = totalPillCount * i; for (int pageIndex = 0; pageIndex < pillSheetGroup.pillSheets.length; pageIndex++) { final pillSheet = pillSheetGroup.pillSheets[pageIndex]; final pillSheetTypes = pillSheetGroup.pillSheets.map((e) => e.pillSheetType).toList(); - final passedCount = passedTotalCount( + final passedCount = summarizedPillSheetTypeTotalCountToPageIndex( pillSheetTypes: pillSheetTypes, pageIndex: pageIndex); final serializedTotalPillNumber = passedCount + pillSheet.typeInfo.totalCount; @@ -91,11 +94,14 @@ List nextPillSheetDateRanges( assert(maxPageCount > 0); // 大体の数を計算 + final totalPillCount = pillSheetGroup.pillSheets + .map((e) => e.pillSheetType.totalCount) + .reduce((value, element) => value + element); final count = max(maxPageCount, pillSheetGroup.pillSheets.length) / pillSheetGroup.pillSheets.length; return List.generate(count.toInt(), (groupPageIndex) { return pillSheetGroup.pillSheets.map((pillSheet) { - final offset = groupPageIndex * pillSheetGroup.totalPillCountIntoGroup; + final offset = groupPageIndex * totalPillCount; final begin = pillSheet.estimatedLastTakenDate.add(Duration(days: 1)); final end = begin.add(Duration(days: Weekday.values.length - 1)); return DateRange( diff --git a/lib/components/organisms/calendar/weekly/weekly_calendar_state.dart b/lib/components/organisms/calendar/weekly/weekly_calendar_state.dart index ac3a96225c..4d9a47ab9f 100644 --- a/lib/components/organisms/calendar/weekly/weekly_calendar_state.dart +++ b/lib/components/organisms/calendar/weekly/weekly_calendar_state.dart @@ -38,7 +38,7 @@ extension WeeklyCalendarStateCompoutedProperties on WeeklyCalendarState { int offsetForStartPositionAtLine(DateTime begin) { return isNecessaryLineBreak(begin) ? 0 - : begin.date().difference(dateRange.begin.date()).inDays; + : daysBetween(dateRange.begin.date(), begin.date()); } DateTime buildDate(Weekday weekday) { diff --git a/lib/components/page/discard_dialog.dart b/lib/components/page/discard_dialog.dart index 290d3656d5..bf4f520af8 100644 --- a/lib/components/page/discard_dialog.dart +++ b/lib/components/page/discard_dialog.dart @@ -1,27 +1,21 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; -import 'package:pilll/components/atoms/buttons.dart'; import 'package:pilll/components/atoms/font.dart'; import 'package:pilll/components/atoms/text_color.dart'; class DiscardDialog extends StatelessWidget { final String title; final Widget message; - final String doneButtonText; - final Function() done; - final Function()? cancel; + final List actions; const DiscardDialog({ Key? key, required this.title, required this.message, - required this.doneButtonText, - required this.done, - this.cancel, + required this.actions, }) : super(key: key); @override Widget build(BuildContext context) { - final cancel = this.cancel; return AlertDialog( title: SvgPicture.asset("images/alert_24.svg", width: 24, height: 24), content: Column( @@ -29,7 +23,11 @@ class DiscardDialog extends StatelessWidget { mainAxisSize: MainAxisSize.min, children: [ if (title.isNotEmpty) ...[ - Text(title, style: FontType.subTitle.merge(TextColorStyle.main)), + Text( + title, + style: FontType.subTitle.merge(TextColorStyle.main), + textAlign: TextAlign.center, + ), SizedBox( height: 15, ), @@ -37,23 +35,7 @@ class DiscardDialog extends StatelessWidget { message, ], ), - actions: [ - SecondaryButton( - text: "キャンセル", - onPressed: cancel != null - ? () => cancel() - : () { - Navigator.of(context).pop(); - }, - ), - SecondaryButton( - text: doneButtonText, - onPressed: () { - done(); - Navigator.of(context).pop(); - }, - ), - ], + actions: actions, ); } } @@ -62,18 +44,15 @@ showDiscardDialog( BuildContext context, { required String title, required String message, - required VoidCallback done, - required String doneText, - VoidCallback? cancel, + required List actions, }) { showDialog( context: context, builder: (context) => DiscardDialog( - title: title, - message: - Text(message, style: FontType.assisting.merge(TextColorStyle.main)), - doneButtonText: doneText, - done: done, - cancel: cancel), + title: title, + message: + Text(message, style: FontType.assisting.merge(TextColorStyle.main)), + actions: actions, + ), ); } diff --git a/lib/domain/calendar/components/pill_sheet_modified_history/components/pill_sheet_modified_history_began_rest_duration.dart b/lib/domain/calendar/components/pill_sheet_modified_history/components/pill_sheet_modified_history_began_rest_duration.dart new file mode 100644 index 0000000000..4fb15aeab6 --- /dev/null +++ b/lib/domain/calendar/components/pill_sheet_modified_history/components/pill_sheet_modified_history_began_rest_duration.dart @@ -0,0 +1,58 @@ +import 'package:flutter/material.dart'; +import 'package:pilll/components/atoms/font.dart'; +import 'package:pilll/components/atoms/text_color.dart'; +import 'package:pilll/domain/calendar/components/pill_sheet_modified_history/components/pill_sheet_modified_history_date_component.dart'; +import 'package:pilll/entity/pill_sheet_modified_history_value.dart'; + +class PillSheetModifiedHistoryBeganRestDuration extends StatelessWidget { + final DateTime estimatedEventCausingDate; + final BeganRestDurationValue? value; + + const PillSheetModifiedHistoryBeganRestDuration({ + Key? key, + required this.value, + required this.estimatedEventCausingDate, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + final value = this.value; + if (value == null) { + return Container(); + } + return Container( + child: Padding( + padding: const EdgeInsets.only(top: 4, bottom: 4), + child: Row( + children: [ + PillSheetModifiedHistoryDate( + estimatedEventCausingDate: estimatedEventCausingDate, + effectivePillNumber: + PillSheetModifiedHistoryDateEffectivePillNumber.hyphen()), + Spacer(), + Container( + width: PillSheetModifiedHistoryTakenActionLayoutWidths.trailing, + child: Row( + children: [ + Container( + child: Text( + "休薬開始", + style: TextStyle( + color: TextColor.main, + fontSize: 12, + fontFamily: FontFamily.japanese, + fontWeight: FontWeight.w400, + ), + textAlign: TextAlign.start, + ), + ), + Spacer(), + ], + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/domain/calendar/components/pill_sheet_modified_history/components/pill_sheet_modified_history_ended_rest_duration.dart b/lib/domain/calendar/components/pill_sheet_modified_history/components/pill_sheet_modified_history_ended_rest_duration.dart new file mode 100644 index 0000000000..c3e36420f1 --- /dev/null +++ b/lib/domain/calendar/components/pill_sheet_modified_history/components/pill_sheet_modified_history_ended_rest_duration.dart @@ -0,0 +1,58 @@ +import 'package:flutter/material.dart'; +import 'package:pilll/components/atoms/font.dart'; +import 'package:pilll/components/atoms/text_color.dart'; +import 'package:pilll/domain/calendar/components/pill_sheet_modified_history/components/pill_sheet_modified_history_date_component.dart'; +import 'package:pilll/entity/pill_sheet_modified_history_value.dart'; + +class PillSheetModifiedHistoryEndedRestDuration extends StatelessWidget { + final DateTime estimatedEventCausingDate; + final EndedRestDurationValue? value; + + const PillSheetModifiedHistoryEndedRestDuration({ + Key? key, + required this.estimatedEventCausingDate, + required this.value, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + final value = this.value; + if (value == null) { + return Container(); + } + return Container( + child: Padding( + padding: const EdgeInsets.only(top: 4, bottom: 4), + child: Row( + children: [ + PillSheetModifiedHistoryDate( + estimatedEventCausingDate: estimatedEventCausingDate, + effectivePillNumber: + PillSheetModifiedHistoryDateEffectivePillNumber.hyphen()), + Spacer(), + Container( + width: PillSheetModifiedHistoryTakenActionLayoutWidths.trailing, + child: Row( + children: [ + Container( + child: Text( + "休薬終了", + style: TextStyle( + color: TextColor.main, + fontSize: 12, + fontFamily: FontFamily.japanese, + fontWeight: FontWeight.w400, + ), + textAlign: TextAlign.start, + ), + ), + Spacer(), + ], + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/domain/calendar/components/pill_sheet_modified_history/pill_sheet_modified_history_card.dart b/lib/domain/calendar/components/pill_sheet_modified_history/pill_sheet_modified_history_card.dart index f87b43a4da..0909ec5cc1 100644 --- a/lib/domain/calendar/components/pill_sheet_modified_history/pill_sheet_modified_history_card.dart +++ b/lib/domain/calendar/components/pill_sheet_modified_history/pill_sheet_modified_history_card.dart @@ -144,18 +144,23 @@ class CalendarPillSheetModifiedHistoryCard extends StatelessWidget { ), ), SizedBox(height: 15), - PrimaryOutlinedButton( - text: "くわしくみる", - onPressed: () { - if (state.trialDeadlineDate == null) { - showPremiumTrialModal(context, () { - showPremiumTrialCompleteModalPreDialog( + SizedBox( + width: 204, + child: PrimaryOutlinedButton( + text: "くわしくみる", + fontSize: 16, + onPressed: () { + if (state.trialDeadlineDate == null) { + showPremiumTrialModal(context, () { + showPremiumTrialCompleteModalPreDialog( + context); + }); + } else { + showPremiumIntroductionSheet( context); - }); - } else { - showPremiumIntroductionSheet(context); - } - }, + } + }, + ), ), ], ), diff --git a/lib/domain/calendar/components/pill_sheet_modified_history/pill_sheet_modified_history_list.dart b/lib/domain/calendar/components/pill_sheet_modified_history/pill_sheet_modified_history_list.dart index 5aa9b20404..ce1d0287a2 100644 --- a/lib/domain/calendar/components/pill_sheet_modified_history/pill_sheet_modified_history_list.dart +++ b/lib/domain/calendar/components/pill_sheet_modified_history/pill_sheet_modified_history_list.dart @@ -1,9 +1,11 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:pilll/domain/calendar/components/pill_sheet_modified_history/components/pill_sheet_modified_history_automatically_recorded_last_taken_date_action.dart'; +import 'package:pilll/domain/calendar/components/pill_sheet_modified_history/components/pill_sheet_modified_history_began_rest_duration.dart'; import 'package:pilll/domain/calendar/components/pill_sheet_modified_history/components/pill_sheet_modified_history_changed_pill_number_action.dart'; import 'package:pilll/domain/calendar/components/pill_sheet_modified_history/components/pill_sheet_modified_history_created_pill_sheet_action.dart'; import 'package:pilll/domain/calendar/components/pill_sheet_modified_history/components/pill_sheet_modified_history_deleted_pill_sheet_action.dart'; +import 'package:pilll/domain/calendar/components/pill_sheet_modified_history/components/pill_sheet_modified_history_ended_rest_duration.dart'; import 'package:pilll/domain/calendar/components/pill_sheet_modified_history/components/pill_sheet_modified_history_ended_pill_sheet_action.dart'; import 'package:pilll/domain/calendar/components/pill_sheet_modified_history/components/pill_sheet_modified_history_monthly_header.dart'; import 'package:pilll/domain/calendar/components/pill_sheet_modified_history/components/pill_sheet_modified_history_revert_taken_pill_action.dart'; @@ -136,6 +138,18 @@ class CalendarPillSheetModifiedHistoryList extends StatelessWidget { return PillSheetModifiedHistoryEndedPillSheetAction( value: history.value.endedPillSheet, ); + case PillSheetModifiedActionType.beganRestDuration: + return PillSheetModifiedHistoryBeganRestDuration( + estimatedEventCausingDate: + history.estimatedEventCausingDate, + value: history.value.beganRestDurationValue, + ); + case PillSheetModifiedActionType.endedRestDuration: + return PillSheetModifiedHistoryEndedRestDuration( + estimatedEventCausingDate: + history.estimatedEventCausingDate, + value: history.value.endedRestDurationValue, + ); } }; diff --git a/lib/domain/calendar/date_range.dart b/lib/domain/calendar/date_range.dart index f8a9dca52d..5773acb566 100644 --- a/lib/domain/calendar/date_range.dart +++ b/lib/domain/calendar/date_range.dart @@ -5,14 +5,14 @@ class DateRange { final DateTime _end; DateTime get begin => _begin.date(); DateTime get end => _end.date(); - int get days => end.difference(begin).inDays; + int get days => daysBetween(begin, end); DateRange(this._begin, this._end); static bool isSameDay(DateTime a, DateTime b) => a.year == b.year && a.month == b.month && a.day == b.day; bool inRange(DateTime date) => - date.isAfter(begin) && date.isBefore(end) || + (date.isAfter(begin) && date.isBefore(end)) || DateRange.isSameDay(date, begin) || DateRange.isSameDay(date, end); DateRange union(DateRange range) { diff --git a/lib/domain/diary/confirm_diary_sheet.dart b/lib/domain/diary/confirm_diary_sheet.dart index ff1afe62d4..da552694bc 100644 --- a/lib/domain/diary/confirm_diary_sheet.dart +++ b/lib/domain/diary/confirm_diary_sheet.dart @@ -1,3 +1,4 @@ +import 'package:pilll/components/atoms/buttons.dart'; import 'package:pilll/components/page/discard_dialog.dart'; import 'package:pilll/domain/diary/post_diary_page.dart'; import 'package:pilll/entity/diary.dart'; @@ -81,15 +82,27 @@ class ConfirmDiarySheet extends HookWidget { context: context, builder: (context) { return DiscardDialog( - title: "日記を削除します", - message: Text("削除された日記は復元ができません", - style: FontType.assisting.merge(TextColorStyle.main)), - doneButtonText: "削除する", - done: () { - int counter = 0; - store.delete().then((value) => Navigator.popUntil( - context, (route) => counter++ >= 1)); - }); + title: "日記を削除します", + message: Text("削除された日記は復元ができません", + style: FontType.assisting.merge(TextColorStyle.main)), + actions: [ + SecondaryButton( + text: "キャンセル", + onPressed: () { + Navigator.of(context).pop(); + }, + ), + SecondaryButton( + text: "削除する", + onPressed: () { + int counter = 0; + store.delete().then((value) => Navigator.popUntil( + context, (route) => counter++ >= 1)); + Navigator.of(context).pop(); + }, + ), + ], + ); }); }, ), diff --git a/lib/domain/initial_setting/initial_setting_state.freezed.dart b/lib/domain/initial_setting/initial_setting_state.freezed.dart index 33d7996e76..374a03fd44 100644 --- a/lib/domain/initial_setting/initial_setting_state.freezed.dart +++ b/lib/domain/initial_setting/initial_setting_state.freezed.dart @@ -187,8 +187,8 @@ class _$InitialSettingStateTearOff { int fromMenstruation = 0, int durationMenstruation = 4, List reminderTimes = const [ - const ReminderTime(hour: 21, minute: 0), - const ReminderTime(hour: 22, minute: 0) + ReminderTime(hour: 21, minute: 0), + ReminderTime(hour: 22, minute: 0) ], bool isOnReminder = true, bool isLoading = false, @@ -402,8 +402,8 @@ class _$_InitialSettingState extends _InitialSettingState { this.fromMenstruation = 0, this.durationMenstruation = 4, this.reminderTimes = const [ - const ReminderTime(hour: 21, minute: 0), - const ReminderTime(hour: 22, minute: 0) + ReminderTime(hour: 21, minute: 0), + ReminderTime(hour: 22, minute: 0) ], this.isOnReminder = true, this.isLoading = false, @@ -422,8 +422,8 @@ class _$_InitialSettingState extends _InitialSettingState { @override final int durationMenstruation; @JsonKey(defaultValue: const [ - const ReminderTime(hour: 21, minute: 0), - const ReminderTime(hour: 22, minute: 0) + ReminderTime(hour: 21, minute: 0), + ReminderTime(hour: 22, minute: 0) ]) @override final List reminderTimes; diff --git a/lib/domain/initial_setting/initial_setting_store.dart b/lib/domain/initial_setting/initial_setting_store.dart index 264f909c03..e818e14492 100644 --- a/lib/domain/initial_setting/initial_setting_store.dart +++ b/lib/domain/initial_setting/initial_setting_store.dart @@ -140,7 +140,7 @@ class InitialSettingStateStore extends StateNotifier { required int pageIndex, required int fromMenstruation, }) { - final offset = passedTotalCount( + final offset = summarizedPillSheetTypeTotalCountToPageIndex( pillSheetTypes: state.pillSheetTypes, pageIndex: pageIndex); state = state.copyWith(fromMenstruation: fromMenstruation + offset); } @@ -158,7 +158,7 @@ class InitialSettingStateStore extends StateNotifier { } int? retrieveMenstruationSelectedPillNumber(int pageIndex) { - final _passedTotalCount = passedTotalCount( + final _passedTotalCount = summarizedPillSheetTypeTotalCountToPageIndex( pillSheetTypes: state.pillSheetTypes, pageIndex: pageIndex); if (_passedTotalCount >= state.fromMenstruation) { return state.fromMenstruation; diff --git a/lib/domain/menstruation/menstruation_card_state.dart b/lib/domain/menstruation/menstruation_card_state.dart index e7bae85633..c4e1c82f5a 100644 --- a/lib/domain/menstruation/menstruation_card_state.dart +++ b/lib/domain/menstruation/menstruation_card_state.dart @@ -16,7 +16,7 @@ abstract class MenstruationCardState implements _$MenstruationCardState { factory MenstruationCardState.future({ required DateTime nextSchedule, }) { - final diff = nextSchedule.difference(today()).inDays; + final diff = daysBetween(today(), nextSchedule); return MenstruationCardState( title: "生理予定日", scheduleDate: nextSchedule, @@ -27,7 +27,7 @@ abstract class MenstruationCardState implements _$MenstruationCardState { factory MenstruationCardState.inTheMiddle({ required DateTime scheduledDate, }) { - final diff = today().difference(scheduledDate).inDays; + final diff = daysBetween(scheduledDate, today()); return MenstruationCardState( title: "生理予定日", scheduleDate: scheduledDate, @@ -42,6 +42,6 @@ abstract class MenstruationCardState implements _$MenstruationCardState { title: "生理開始日", scheduleDate: menstruation.beginDate, countdownString: - "${today().difference(menstruation.beginDate).inDays + 1}日目", + "${daysBetween(menstruation.beginDate, today()) + 1}日目", ); } diff --git a/lib/domain/menstruation/menstruation_state.dart b/lib/domain/menstruation/menstruation_state.dart index 7e661f7b3b..2dc7371617 100644 --- a/lib/domain/menstruation/menstruation_state.dart +++ b/lib/domain/menstruation/menstruation_state.dart @@ -5,7 +5,6 @@ import 'package:pilll/entity/pill_sheet_group.dart'; import 'package:pilll/entity/setting.dart'; import 'package:pilll/util/datetime/date_compare.dart'; import 'package:pilll/util/formatter/date_time_formatter.dart'; -import 'package:flutter/material.dart'; import 'package:pilll/entity/weekday.dart'; import 'package:pilll/util/datetime/day.dart'; @@ -65,7 +64,7 @@ List> _calendarDataSource() { Weekday.values.last.index - WeekdayFunctions.weekdayFromDate(end).index; end = end.add(Duration(days: endWeekdayOffset)); - var diffDay = DateTimeRange(start: begin, end: end).duration.inDays; + var diffDay = daysBetween(begin, end); diffDay += Weekday.values.length - diffDay % Weekday.values.length; List days = []; for (int i = 0; i < diffDay; i++) { diff --git a/lib/domain/menstruation_edit/menstruation_edit_page.dart b/lib/domain/menstruation_edit/menstruation_edit_page.dart index 60c8fd0777..4d912e4305 100644 --- a/lib/domain/menstruation_edit/menstruation_edit_page.dart +++ b/lib/domain/menstruation_edit/menstruation_edit_page.dart @@ -80,17 +80,29 @@ class MenstruationEditPage extends HookWidget { builder: (context) => DiscardDialog( title: "生理期間を削除しますか?", message: Text(""), - doneButtonText: "削除する", - done: () => store - .delete() - .then((_) => didEndDelete()) - .then((_) => analytics.logEvent( - name: "pressed_delete_menstruation")), - cancel: () { - analytics.logEvent( - name: "cancelled_delete_menstruation"); - Navigator.of(context).pop(); - }, + actions: [ + SecondaryButton( + text: "キャンセル", + onPressed: () { + analytics.logEvent( + name: + "cancelled_delete_menstruation"); + Navigator.of(context).pop(); + }, + ), + SecondaryButton( + text: "削除する", + onPressed: () { + store + .delete() + .then((_) => didEndDelete()) + .then((_) => analytics.logEvent( + name: + "pressed_delete_menstruation")); + Navigator.of(context).pop(); + }, + ), + ], ), ); } else if (store.isDismissWhenSaveButtonPressed()) { diff --git a/lib/domain/record/components/button/record_page_button.dart b/lib/domain/record/components/button/record_page_button.dart index 43f5a53594..31deb7ac5b 100644 --- a/lib/domain/record/components/button/record_page_button.dart +++ b/lib/domain/record/components/button/record_page_button.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:pilll/domain/record/components/button/cancel_button.dart'; +import 'package:pilll/domain/record/components/button/rest_duration_button.dart'; import 'package:pilll/domain/record/components/button/taken_button.dart'; import 'package:pilll/entity/pill_sheet.dart'; @@ -12,7 +13,9 @@ class RecordPageButton extends StatelessWidget { }) : super(key: key); Widget build(BuildContext context) { - if (currentPillSheet.isAllTaken) + if (currentPillSheet.activeRestDuration != null) + return RestDurationButton(); + else if (currentPillSheet.isAllTaken) return CancelButton(currentPillSheet); else return TakenButton( diff --git a/lib/domain/record/components/button/rest_duration_button.dart b/lib/domain/record/components/button/rest_duration_button.dart new file mode 100644 index 0000000000..6274d0ebe1 --- /dev/null +++ b/lib/domain/record/components/button/rest_duration_button.dart @@ -0,0 +1,20 @@ +import 'package:flutter/material.dart'; +import 'package:pilll/components/atoms/button.dart'; +import 'package:pilll/components/atoms/color.dart'; +import 'package:pilll/components/atoms/text_color.dart'; + +class RestDurationButton extends StatelessWidget { + RestDurationButton(); + Widget build(BuildContext context) { + return SizedBox( + width: 180, + height: 44, + child: TextButton( + style: TextButton.styleFrom(backgroundColor: PilllColors.disable), + child: Text("休薬中", + style: ButtonTextStyle.main.merge(TextColorStyle.lightGray)), + onPressed: null, + ), + ); + } +} diff --git a/lib/domain/record/components/header/today_taken_pill_number.dart b/lib/domain/record/components/header/today_taken_pill_number.dart index fc8b9551f7..a1c2470aa3 100644 --- a/lib/domain/record/components/header/today_taken_pill_number.dart +++ b/lib/domain/record/components/header/today_taken_pill_number.dart @@ -44,7 +44,8 @@ class TodayTakenPillNumber extends StatelessWidget { final activedPillSheet = this.pillSheetGroup?.activedPillSheet; if (pillSheetGroup == null || activedPillSheet == null || - pillSheetGroup.isDeactived) { + pillSheetGroup.isDeactived || + activedPillSheet.activeRestDuration != null) { return Padding( padding: EdgeInsets.only(top: 8), child: Text("-", 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 77bf63a193..35582aeafe 100644 --- a/lib/domain/record/components/notification_bar/notification_bar_state.dart +++ b/lib/domain/record/components/notification_bar/notification_bar_state.dart @@ -36,12 +36,17 @@ abstract class NotificationBarState implements _$NotificationBarState { if (activedPillSheet == null) { return null; } - if (activedPillSheet.pillSheetType.isNotExistsNotTakenDuration) { - return null; + final restDuration = activedPillSheet.activeRestDuration; + if (restDuration != null) { + final day = daysBetween(restDuration.beginDate.date(), today()) + 1; + return "休薬${activedPillSheet.pillSheetType.notTakenWord}$day日目"; } + if (activedPillSheet.typeInfo.dosingPeriod < activedPillSheet.todayPillNumber) { - return "${activedPillSheet.pillSheetType.notTakenWord}期間中"; + final day = activedPillSheet.todayPillNumber - + activedPillSheet.typeInfo.dosingPeriod; + return "${activedPillSheet.pillSheetType.notTakenWord}$day日目"; } final threshold = 4; @@ -69,7 +74,7 @@ abstract class NotificationBarState implements _$NotificationBarState { return null; } - final diff = trialDeadlineDate.difference(now()).inDays + 1; + final diff = daysBetween(now(), trialDeadlineDate) + 1; if (diff < 0) { return null; } diff --git a/lib/domain/record/components/pill_sheet/components/record_page_pill_option.dart b/lib/domain/record/components/pill_sheet/components/record_page_pill_option.dart new file mode 100644 index 0000000000..93a62641bb --- /dev/null +++ b/lib/domain/record/components/pill_sheet/components/record_page_pill_option.dart @@ -0,0 +1,92 @@ +import 'package:flutter/material.dart'; +import 'package:pilll/components/atoms/buttons.dart'; +import 'package:pilll/components/organisms/pill_sheet/pill_sheet_view_layout.dart'; +import 'package:pilll/components/page/discard_dialog.dart'; +import 'package:pilll/domain/record/components/pill_sheet/components/record_page_rest_duration_dialog.dart'; +import 'package:pilll/domain/record/record_page_store.dart'; +import 'package:pilll/entity/pill_sheet.dart'; +import 'package:pilll/entity/pill_sheet_group.dart'; + +class RecordPagePillOption extends StatelessWidget { + final RecordPageStore store; + final PillSheetGroup pillSheetGroup; + final PillSheet activedPillSheet; + + const RecordPagePillOption({ + Key? key, + required this.store, + required this.pillSheetGroup, + required this.activedPillSheet, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + final RestDuration? restDuration = activedPillSheet.activeRestDuration; + + return Container( + width: PillSheetViewLayout.width, + child: Row(children: [ + Spacer(), + if (!pillSheetGroup.hasPillSheetRestDuration) + SizedBox( + width: 80, + child: PrimaryOutlinedButton( + text: restDuration == null ? "休薬する" : "休薬終了", + fontSize: 12, + onPressed: () async { + if (restDuration == null) { + if (activedPillSheet.todayPillNumber - 1 > + activedPillSheet.lastTakenPillNumber) { + showDiscardDialog( + context, + title: "未服用のピルがある場合\n休薬できません", + message: + "ピル番号をタップして昨日までのピルを服用済みにしてから「休薬する」を押してください。それよりも前から休薬したい場合は、「今日飲むピル番号」を調整してください。", + actions: [ + SecondaryButton( + text: "閉じる", + onPressed: () { + Navigator.of(context).pop(); + }, + ), + ], + ); + } else { + showRecordPageRestDurationDialog(context, () async { + Navigator.of(context).pop(); + await store.beginResting( + pillSheetGroup: pillSheetGroup, + activedPillSheet: activedPillSheet, + ); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + duration: Duration( + seconds: 2, + ), + content: Text("休薬期間が始まりました"), + ), + ); + }); + } + } else { + await store.endResting( + pillSheetGroup: pillSheetGroup, + activedPillSheet: activedPillSheet, + restDuration: restDuration, + ); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + duration: Duration( + seconds: 2, + ), + content: Text("休薬期間が終了しました"), + ), + ); + } + }, + ), + ), + ]), + ); + } +} diff --git a/lib/domain/record/components/pill_sheet/components/record_page_rest_duration_dialog.dart b/lib/domain/record/components/pill_sheet/components/record_page_rest_duration_dialog.dart new file mode 100644 index 0000000000..a52608d49f --- /dev/null +++ b/lib/domain/record/components/pill_sheet/components/record_page_rest_duration_dialog.dart @@ -0,0 +1,61 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:pilll/components/atoms/buttons.dart'; +import 'package:pilll/components/atoms/font.dart'; +import 'package:pilll/components/atoms/text_color.dart'; + +class RecordPageRestDurationDialog extends StatelessWidget { + final VoidCallback onDone; + + const RecordPageRestDurationDialog({ + Key? key, + required this.onDone, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return AlertDialog( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(20.0))), + contentPadding: EdgeInsets.only(left: 24, right: 24, top: 32), + actionsPadding: EdgeInsets.only(left: 24, right: 24), + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text("今日から休薬しますか?", + style: FontType.subTitle.merge(TextColorStyle.main)), + SizedBox(height: 24), + Text("休薬するとピル番号は進みません", + style: FontType.assisting.merge(TextColorStyle.main)), + SizedBox(height: 24), + SvgPicture.asset("images/explain_rest_duration.svg"), + SizedBox(height: 24), + ], + ), + actions: [ + PrimaryOutlinedButton( + onPressed: () => onDone(), + fontSize: 16, + text: "休薬する", + ), + Center( + child: SecondaryButton( + text: "閉じる", + onPressed: () { + Navigator.of(context).pop(); + }, + ), + ), + ], + ); + } +} + +showRecordPageRestDurationDialog(BuildContext context, VoidCallback onDone) { + showDialog( + context: context, + builder: (context) => RecordPageRestDurationDialog( + onDone: onDone, + ), + ); +} diff --git a/lib/domain/record/components/pill_sheet/record_page_pill_sheet.dart b/lib/domain/record/components/pill_sheet/record_page_pill_sheet.dart index 919972880e..1d16dfa10d 100644 --- a/lib/domain/record/components/pill_sheet/record_page_pill_sheet.dart +++ b/lib/domain/record/components/pill_sheet/record_page_pill_sheet.dart @@ -14,6 +14,7 @@ import 'package:pilll/entity/pill_sheet_group.dart'; import 'package:pilll/entity/pill_sheet_type.dart'; import 'package:pilll/entity/setting.dart'; import 'package:pilll/entity/weekday.dart'; +import 'package:pilll/util/datetime/day.dart'; class RecordPagePillSheet extends StatelessWidget { final PillSheetGroup pillSheetGroup; @@ -124,8 +125,8 @@ class RecordPagePillSheet extends StatelessWidget { required int pillNumberIntoPillSheet, required int pageIndex, }) { - final date = - pillSheet.beginingDate.add(Duration(days: pillNumberIntoPillSheet - 1)); + final DateTime date = + calculatedDateOfAppearancePill(pillSheet, pillNumberIntoPillSheet); final isDateMode = () { if (!(state.isPremium || state.isTrial)) { return false; @@ -204,8 +205,8 @@ class RecordPagePillSheet extends StatelessWidget { final pillSheetTypes = pillSheetGroup.pillSheets.map((e) => e.pillSheetType).toList(); - final passedCount = - passedTotalCount(pillSheetTypes: pillSheetTypes, pageIndex: pageIndex); + final passedCount = summarizedPillSheetTypeTotalCountToPageIndex( + pillSheetTypes: pillSheetTypes, pageIndex: pageIndex); final serialiedPillNumber = passedCount + pillNumberIntoPillSheet; final menstruationRangeList = @@ -220,6 +221,32 @@ class RecordPagePillSheet extends StatelessWidget { .isNotEmpty; return isContainedMenstruationDuration; } + + static DateTime calculatedDateOfAppearancePill( + PillSheet pillSheet, int pillNumberIntoPillSheet) { + final date = pillSheet.beginingDate + .add(Duration(days: pillNumberIntoPillSheet - 1)) + .date(); + if (pillSheet.restDurations.isEmpty) { + return date; + } + + final distance = + pillSheet.restDurations.fold(0, (int result, restDuration) { + if (date.isBefore(restDuration.beginDate.date())) { + return result; + } + + final endDate = restDuration.endDate?.date(); + if (endDate != null && date.isAfter(endDate)) { + return result + daysBetween(restDuration.beginDate.date(), endDate); + } else { + return result + daysBetween(restDuration.beginDate.date(), today()); + } + }); + + return date.add(Duration(days: distance)); + } } class _MenstruationRange { diff --git a/lib/domain/record/components/pill_sheet/record_page_pill_sheet_list.dart b/lib/domain/record/components/pill_sheet/record_page_pill_sheet_list.dart index fe700741a0..443f21b740 100644 --- a/lib/domain/record/components/pill_sheet/record_page_pill_sheet_list.dart +++ b/lib/domain/record/components/pill_sheet/record_page_pill_sheet_list.dart @@ -36,12 +36,12 @@ class RecordPagePillSheetList extends HookWidget { children: [ Container( height: PillSheetViewLayout.calcHeight( - PillSheetViewLayout.mostLargePillSheetType(pillSheetGroup - .pillSheets - .map((e) => e.pillSheetType) - .toList()) - .numberOfLineInPillSheet, - false), + PillSheetViewLayout.mostLargePillSheetType(pillSheetGroup.pillSheets + .map((e) => e.pillSheetType) + .toList()) + .numberOfLineInPillSheet, + false, + ), child: PageView( clipBehavior: Clip.none, controller: pageController, diff --git a/lib/domain/record/record_page.dart b/lib/domain/record/record_page.dart index 9c2474d40e..95eebf779d 100644 --- a/lib/domain/record/record_page.dart +++ b/lib/domain/record/record_page.dart @@ -4,6 +4,7 @@ import 'package:pilll/domain/premium_trial/premium_trial_complete_modal.dart'; import 'package:pilll/domain/record/components/adding/record_page_adding_pill_sheet.dart'; import 'package:pilll/domain/record/components/button/record_page_button.dart'; import 'package:pilll/domain/record/components/notification_bar/notification_bar.dart'; +import 'package:pilll/domain/record/components/pill_sheet/components/record_page_pill_option.dart'; import 'package:pilll/domain/record/components/pill_sheet/record_page_pill_sheet_list.dart'; import 'package:pilll/domain/record/record_page_state.dart'; import 'package:pilll/domain/record/record_page_store.dart'; @@ -38,7 +39,8 @@ class RecordPage extends HookWidget { }); }); - final currentPillSheet = state.pillSheetGroup?.activedPillSheet; + final pillSheetGroup = state.pillSheetGroup; + final activedPillSheet = pillSheetGroup?.activedPillSheet; final settingEntity = state.setting; if (settingEntity == null || !state.firstLoadIsEnded) { return Indicator(); @@ -68,16 +70,18 @@ class RecordPage extends HookWidget { child: Column( children: [ NotificationBar(state), - SizedBox(height: 64), + SizedBox(height: 37), _content(context, settingEntity, state, store), ], ), ), ), - if (currentPillSheet != null && !state.isDeactived) + if (activedPillSheet != null && + pillSheetGroup != null && + !pillSheetGroup.isDeactived) Positioned( bottom: 20, - child: RecordPageButton(currentPillSheet: currentPillSheet), + child: RecordPageButton(currentPillSheet: activedPillSheet), ), ], ), @@ -91,19 +95,33 @@ class RecordPage extends HookWidget { RecordPageState state, RecordPageStore store, ) { - if (state.isDeactived) + final pillSheetGroup = state.pillSheetGroup; + final activedPillSheet = pillSheetGroup?.activedPillSheet; + if (activedPillSheet == null || + pillSheetGroup == null || + pillSheetGroup.isDeactived) return RecordPageAddingPillSheet( context: context, store: store, setting: settingEntity, ); - if (!state.isDeactived) - return RecordPagePillSheetList( - state: state, - store: store, - setting: settingEntity, + else + return Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + RecordPagePillOption( + store: store, + pillSheetGroup: pillSheetGroup, + activedPillSheet: activedPillSheet, + ), + SizedBox(height: 16), + RecordPagePillSheetList( + state: state, + store: store, + setting: settingEntity, + ), + ], ); - return Container(); } Future _showMigrateInfoDialog( diff --git a/lib/domain/record/record_page_state.dart b/lib/domain/record/record_page_state.dart index f278b3308c..a3c3ff09b1 100644 --- a/lib/domain/record/record_page_state.dart +++ b/lib/domain/record/record_page_state.dart @@ -30,11 +30,6 @@ abstract class RecordPageState implements _$RecordPageState { return pillSheetGroup?.activedPillSheet?.groupIndex ?? 0; } - bool get isDeactived { - final pillSheetGroup = this.pillSheetGroup; - return pillSheetGroup == null || pillSheetGroup.isDeactived; - } - bool get shouldShowTrial { if (beginTrialDate != null) { return false; diff --git a/lib/domain/record/record_page_store.dart b/lib/domain/record/record_page_store.dart index 86b873f51e..cd3feabb7c 100644 --- a/lib/domain/record/record_page_store.dart +++ b/lib/domain/record/record_page_store.dart @@ -173,7 +173,7 @@ class RecordPageStore extends StateNotifier { batch, setting.pillSheetTypes.asMap().keys.map((pageIndex) { final pillSheetType = setting.pillSheetTypes[pageIndex]; - final offset = passedTotalCount( + final offset = summarizedPillSheetTypeTotalCountToPageIndex( pillSheetTypes: setting.pillSheetTypes, pageIndex: pageIndex); return PillSheet( typeInfo: pillSheetType.typeInfo, @@ -350,6 +350,9 @@ class RecordPageStore extends StateNotifier { required int pillNumberIntoPillSheet, required PillSheet pillSheet, }) { + if (state.pillSheetGroup?.activedPillSheet?.activeRestDuration != null) { + return false; + } final activedPillSheet = state.pillSheetGroup?.activedPillSheet; if (activedPillSheet == null) { throw FormatException("pill sheet not found"); @@ -401,4 +404,66 @@ class RecordPageStore extends StateNotifier { final updatedSetting = setting.copyWith(pillSheetTypes: copied); state = state.copyWith(setting: updatedSetting); } + + Future beginResting({ + required PillSheetGroup pillSheetGroup, + required PillSheet activedPillSheet, + }) async { + final restDuration = RestDuration( + beginDate: now(), + createdDate: now(), + ); + final updatedPillSheet = activedPillSheet.copyWith( + restDurations: activedPillSheet.restDurations..add(restDuration), + ); + final updatedPillSheetGroup = pillSheetGroup.replaced(updatedPillSheet); + + final batch = _batchFactory.batch(); + _pillSheetService.update(batch, updatedPillSheetGroup.pillSheets); + _pillSheetGroupService.update(batch, updatedPillSheetGroup); + _pillSheetModifiedHistoryService.add( + batch, + PillSheetModifiedHistoryServiceActionFactory + .createBeganRestDurationAction( + pillSheetGroupID: pillSheetGroup.id, + before: activedPillSheet, + after: updatedPillSheet, + restDuration: restDuration, + ), + ); + + await batch.commit(); + } + + Future endResting({ + required PillSheetGroup pillSheetGroup, + required PillSheet activedPillSheet, + required RestDuration restDuration, + }) async { + final updatedRestDuration = restDuration.copyWith(endDate: now()); + final updatedPillSheet = activedPillSheet.copyWith( + restDurations: activedPillSheet.restDurations + ..replaceRange( + activedPillSheet.restDurations.length - 1, + activedPillSheet.restDurations.length, + [updatedRestDuration], + ), + ); + final updatedPillSheetGroup = pillSheetGroup.replaced(updatedPillSheet); + + final batch = _batchFactory.batch(); + _pillSheetService.update(batch, updatedPillSheetGroup.pillSheets); + _pillSheetGroupService.update(batch, updatedPillSheetGroup); + _pillSheetModifiedHistoryService.add( + batch, + PillSheetModifiedHistoryServiceActionFactory + .createEndedRestDurationAction( + pillSheetGroupID: pillSheetGroup.id, + before: activedPillSheet, + after: updatedPillSheet, + restDuration: updatedRestDuration, + ), + ); + await batch.commit(); + } } diff --git a/lib/domain/settings/components/rows/pill_sheet_remove.dart b/lib/domain/settings/components/rows/pill_sheet_remove.dart index 979ab47b7d..ef546ca264 100644 --- a/lib/domain/settings/components/rows/pill_sheet_remove.dart +++ b/lib/domain/settings/components/rows/pill_sheet_remove.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:pilll/analytics.dart'; +import 'package:pilll/components/atoms/buttons.dart'; import 'package:pilll/components/atoms/font.dart'; import 'package:pilll/components/atoms/text_color.dart'; import 'package:pilll/components/page/discard_dialog.dart'; @@ -23,35 +24,46 @@ class PillSheetRemoveRow extends HookWidget { context: context, builder: (_) { return DiscardDialog( - title: "ピルシートをすべて破棄しますか?", - message: RichText( - textAlign: TextAlign.start, - text: TextSpan( - children: [ - TextSpan( - text: "現在表示されている", - style: FontType.assisting.merge(TextColorStyle.main), - ), - TextSpan( - text: "すべてのピルシート", - style: - FontType.assistingBold.merge(TextColorStyle.main), - ), - TextSpan( - text: "が破棄されます", - style: FontType.assisting.merge(TextColorStyle.main), - ), - ], - ), + title: "ピルシートをすべて破棄しますか?", + message: RichText( + textAlign: TextAlign.start, + text: TextSpan( + children: [ + TextSpan( + text: "現在表示されている", + style: FontType.assisting.merge(TextColorStyle.main), + ), + TextSpan( + text: "すべてのピルシート", + style: FontType.assistingBold.merge(TextColorStyle.main), + ), + TextSpan( + text: "が破棄されます", + style: FontType.assisting.merge(TextColorStyle.main), + ), + ], ), - doneButtonText: "破棄する", - done: () { - store.deletePillSheet().catchError((error) { - showErrorAlert(context, - message: - "ピルシートがすでに削除されています。表示等に問題がある場合は設定タブから「お問い合わせ」ください"); - }, test: (error) => error is PillSheetIsNotExists); - }); + ), + actions: [ + SecondaryButton( + text: "キャンセル", + onPressed: () { + Navigator.of(context).pop(); + }, + ), + SecondaryButton( + text: "破棄する", + onPressed: () { + store.deletePillSheet().catchError((error) { + showErrorAlert(context, + message: + "ピルシートがすでに削除されています。表示等に問題がある場合は設定タブから「お問い合わせ」ください"); + }, test: (error) => error is PillSheetIsNotExists); + Navigator.of(context).pop(); + }, + ), + ], + ); }, ); }, diff --git a/lib/domain/settings/information_for_before_major_update.dart b/lib/domain/settings/information_for_before_major_update.dart index a938b830fa..a294ca0bbe 100644 --- a/lib/domain/settings/information_for_before_major_update.dart +++ b/lib/domain/settings/information_for_before_major_update.dart @@ -17,12 +17,12 @@ class InformationForBeforeMigrate132 extends StatelessWidget { int _latestPillNumber() { final last = DateTime.parse(this.salvagedOldLastTakenDate); final start = DateTime.parse(this.salvagedOldStartTakenDate); - return last.difference(start).inDays % 28 + 1; + return daysBetween(start, last) % 28 + 1; } int _todayPillNumber() { final start = DateTime.parse(this.salvagedOldStartTakenDate); - return today().difference(start).inDays % 28 + 1; + return daysBetween(start, today()) % 28 + 1; } @override diff --git a/lib/domain/settings/menstruation/setting_menstruation_store.dart b/lib/domain/settings/menstruation/setting_menstruation_store.dart index dfc21b523c..e4105f2b84 100644 --- a/lib/domain/settings/menstruation/setting_menstruation_store.dart +++ b/lib/domain/settings/menstruation/setting_menstruation_store.dart @@ -22,7 +22,7 @@ class SettingMenstruationStateStore required int pageIndex, required int fromMenstruation, }) { - final offset = passedTotalCount( + final offset = summarizedPillSheetTypeTotalCountToPageIndex( pillSheetTypes: setting.pillSheetTypes, pageIndex: pageIndex); return _settingService.update(setting.copyWith( pillNumberForFromMenstruation: fromMenstruation + offset)); @@ -48,7 +48,7 @@ class SettingMenstruationStateStore Setting setting, int pageIndex, ) { - final _passedTotalCount = passedTotalCount( + final _passedTotalCount = summarizedPillSheetTypeTotalCountToPageIndex( pillSheetTypes: setting.pillSheetTypes, pageIndex: pageIndex); if (_passedTotalCount >= setting.pillNumberForFromMenstruation) { return setting.pillNumberForFromMenstruation; diff --git a/lib/domain/settings/setting_account_list/components/delete_user_button.dart b/lib/domain/settings/setting_account_list/components/delete_user_button.dart index 9138d73575..cfa89c5957 100644 --- a/lib/domain/settings/setting_account_list/components/delete_user_button.dart +++ b/lib/domain/settings/setting_account_list/components/delete_user_button.dart @@ -23,10 +23,21 @@ class DeleteUserButton extends StatelessWidget { context, title: "ユーザー情報が削除されます", message: "退会をするとすべてデータが削除され、二度と同じアカウントでログインができなくなります。", - doneText: "退会する", - done: () async { - await _delete(context); - }, + actions: [ + SecondaryButton( + text: "キャンセル", + onPressed: () { + Navigator.of(context).pop(); + }, + ), + SecondaryButton( + text: "退会する", + onPressed: () async { + await _delete(context); + Navigator.of(context).pop(); + }, + ), + ], ); }, text: "退会する", @@ -53,18 +64,29 @@ class DeleteUserButton extends StatelessWidget { context, title: "再ログインしてください", message: "退会前に本人確認のために再ログインをしてください。再ログイン後、自動的に退会処理が始まります", - done: () async { - if (isLinkedApple()) { - await appleReauthentification(); - } else if (isLinkedGoogle()) { - await googleReauthentification(); - } else { - errorLogger.log("it is not cooperate account"); - exit(1); - } - await _delete(context); - }, - doneText: "再ログイン", + actions: [ + SecondaryButton( + text: "キャンセル", + onPressed: () { + Navigator.of(context).pop(); + }, + ), + SecondaryButton( + text: "再ログイン", + onPressed: () async { + if (isLinkedApple()) { + await appleReauthentification(); + } else if (isLinkedGoogle()) { + await googleReauthentification(); + } else { + errorLogger.log("it is not cooperate account"); + exit(1); + } + await _delete(context); + Navigator.of(context).pop(); + }, + ), + ], ); } else { errorLogger.recordError(error, stackTrace); diff --git a/lib/domain/settings/setting_page.dart b/lib/domain/settings/setting_page.dart index d850158152..319912afe8 100644 --- a/lib/domain/settings/setting_page.dart +++ b/lib/domain/settings/setting_page.dart @@ -1,4 +1,5 @@ import 'package:pilll/analytics.dart'; +import 'package:pilll/components/atoms/buttons.dart'; import 'package:pilll/components/atoms/font.dart'; import 'package:pilll/components/page/discard_dialog.dart'; import 'package:pilll/domain/settings/components/rows/creating_new_pillsheet.dart'; @@ -139,7 +140,7 @@ class SettingPage extends HookWidget { NotificationTimeRow(setting: setting), _separator(), if (activedPillSheet != null && - activedPillSheet.hasRestDuration) ...[ + activedPillSheet.pillSheetHasRestOrFakeDuration) ...[ NotificationInRestDuration( setting: setting, pillSheet: activedPillSheet), _separator(), @@ -237,17 +238,23 @@ class SettingPage extends HookWidget { if (signOut == null) { return; } - showDiscardDialog( - context, - title: "サインアウトします", - message: ''' + showDiscardDialog(context, title: "サインアウトします", message: ''' これは開発用のオプションです。サインアウトあとはアプリを再起動してお試しください。初期設定から始まります -''', - done: () async { - await signOut(); - }, - doneText: "サインアウト", - ); +''', actions: [ + SecondaryButton( + text: "キャンセル", + onPressed: () { + Navigator.of(context).pop(); + }, + ), + SecondaryButton( + text: "サインアウト", + onPressed: () async { + await signOut(); + Navigator.of(context).pop(); + }, + ), + ]); }, onLongPress: () { final deleteUser = Environment.deleteUser; @@ -260,10 +267,21 @@ class SettingPage extends HookWidget { message: ''' これは開発用のオプションです。ユーザーを削除したあとはアプリを再起動してからやり直してください。初期設定から始まります ''', - done: () async { - await deleteUser(); - }, - doneText: "削除", + actions: [ + SecondaryButton( + text: "キャンセル", + onPressed: () { + Navigator.of(context).pop(); + }, + ), + SecondaryButton( + text: "削除", + onPressed: () async { + await deleteUser(); + Navigator.of(context).pop(); + }, + ), + ], ); }, ), diff --git a/lib/domain/settings/today_pill_number/setting_today_pill_number_store.dart b/lib/domain/settings/today_pill_number/setting_today_pill_number_store.dart index b45618dd31..09b4db244a 100644 --- a/lib/domain/settings/today_pill_number/setting_today_pill_number_store.dart +++ b/lib/domain/settings/today_pill_number/setting_today_pill_number_store.dart @@ -9,6 +9,7 @@ import 'package:pilll/entity/pill_sheet_type.dart'; import 'package:pilll/service/pill_sheet.dart'; import 'package:pilll/service/pill_sheet_group.dart'; import 'package:pilll/service/pill_sheet_modified_history.dart'; +import 'package:pilll/util/datetime/day.dart'; import 'package:riverpod/riverpod.dart'; final settingTodayPillNumberStoreProvider = @@ -60,42 +61,49 @@ class SettingTodayPillNumberStateStore required PillSheetGroup pillSheetGroup, required PillSheet activedPillSheet, }) async { - final currentPillNumberIntoGroup = pillSheetGroup.serializedTodayPillNumber; - if (currentPillNumberIntoGroup == null) { - throw FormatException("有効なピルシートのデータが見つかりませんでした"); - } - final batch = _batchFactory.batch(); final pillSheetTypes = pillSheetGroup.pillSheets.map((e) => e.pillSheetType).toList(); - final nextSerializedPillNumber = passedTotalCount( - pillSheetTypes: pillSheetTypes, - pageIndex: state.selectedPillSheetPageIndex, - ) + - state.selectedPillMarkNumberIntoPillSheet; + final nextSerializedPillNumber = + summarizedPillSheetTypeTotalCountToPageIndex( + pillSheetTypes: pillSheetTypes, + pageIndex: state.selectedPillSheetPageIndex, + ) + + state.selectedPillMarkNumberIntoPillSheet; + final firstPilSheetBeginDate = + today().subtract(Duration(days: nextSerializedPillNumber - 1)); - final distance = nextSerializedPillNumber - currentPillNumberIntoGroup; final List updatedPillSheets = []; pillSheetGroup.pillSheets.asMap().keys.forEach((index) { final pillSheet = pillSheetGroup.pillSheets[index]; - final beginingDate = - pillSheet.beginingDate.subtract(Duration(days: distance)); + + final DateTime beginDate; + if (index == 0) { + beginDate = firstPilSheetBeginDate; + } else { + final passedTotalCount = summarizedPillSheetTypeTotalCountToPageIndex( + pillSheetTypes: pillSheetTypes, pageIndex: index); + beginDate = + firstPilSheetBeginDate.add(Duration(days: passedTotalCount)); + } + final DateTime? lastTakenDate; if (state.selectedPillSheetPageIndex == index) { - lastTakenDate = beginingDate + lastTakenDate = beginDate .add(Duration(days: state.selectedPillMarkNumberIntoPillSheet - 2)); } else if (state.selectedPillSheetPageIndex > index) { - lastTakenDate = beginingDate + lastTakenDate = beginDate .add(Duration(days: pillSheet.pillSheetType.totalCount - 1)); } else { // state.selectedPillMarkNumberIntoPillSheet < index lastTakenDate = null; } + final updatedPillSheet = pillSheet.copyWith( - beginingDate: beginingDate, - lastTakenDate: lastTakenDate, - ); + beginingDate: beginDate, + lastTakenDate: lastTakenDate, + restDurations: []); updatedPillSheets.add(updatedPillSheet); }); @@ -122,7 +130,7 @@ int _pillNumberIntoPillSheet({ }) { final pillSheetTypes = pillSheetGroup.pillSheets.map((e) => e.pillSheetType).toList(); - final _passedTotalCount = passedTotalCount( + final _passedTotalCount = summarizedPillSheetTypeTotalCountToPageIndex( pillSheetTypes: pillSheetTypes, pageIndex: activedPillSheet.groupIndex); if (_passedTotalCount >= activedPillSheet.todayPillNumber) { return activedPillSheet.todayPillNumber; diff --git a/lib/entity/pill_sheet.dart b/lib/entity/pill_sheet.dart index 88d5f6dfee..7f38a20ff5 100644 --- a/lib/entity/pill_sheet.dart +++ b/lib/entity/pill_sheet.dart @@ -32,6 +32,33 @@ abstract class PillSheetTypeInfo with _$PillSheetTypeInfo { _$_$_PillSheetTypeInfoToJson(this as _$_PillSheetTypeInfo); } +@freezed +abstract class RestDuration with _$RestDuration { + @JsonSerializable(explicitToJson: true) + factory RestDuration({ + @JsonKey( + fromJson: NonNullTimestampConverter.timestampToDateTime, + toJson: NonNullTimestampConverter.dateTimeToTimestamp, + ) + required DateTime beginDate, + @JsonKey( + fromJson: TimestampConverter.timestampToDateTime, + toJson: TimestampConverter.dateTimeToTimestamp, + ) + DateTime? endDate, + @JsonKey( + fromJson: NonNullTimestampConverter.timestampToDateTime, + toJson: NonNullTimestampConverter.dateTimeToTimestamp, + ) + required DateTime createdDate, + }) = _RestDuration; + + factory RestDuration.fromJson(Map json) => + _$RestDurationFromJson(json); + Map toJson() => + _$_$_RestDurationToJson(this as _$_RestDuration); +} + @freezed abstract class PillSheet implements _$PillSheet { String? get documentID => id; @@ -68,6 +95,8 @@ abstract class PillSheet implements _$PillSheet { DateTime? deletedAt, @Default(0) int groupIndex, + @Default([]) + List restDurations, }) = _PillSheet; factory PillSheet.create(PillSheetType type) => PillSheet( typeInfo: type.typeInfo, @@ -83,12 +112,39 @@ abstract class PillSheet implements _$PillSheet { PillSheetTypeFunctions.fromRawPath(typeInfo.pillSheetTypeReferencePath); int get todayPillNumber { - return today().difference(beginingDate.date()).inDays + 1; + return daysBetween(beginingDate.date(), today()) - + summarizedRestDuration(restDurations) + + 1; } - int get lastTakenPillNumber => lastTakenDate == null - ? 0 - : lastTakenDate!.date().difference(beginingDate.date()).inDays + 1; + int get lastTakenPillNumber { + final lastTakenDate = this.lastTakenDate; + if (lastTakenDate == null) { + return 0; + } + + final lastTakenPillNumber = + daysBetween(beginingDate.date(), lastTakenDate.date()) + 1; + if (restDurations.isEmpty) { + return lastTakenPillNumber; + } + + final summarizedRestDuration = restDurations.map((e) { + if (!e.beginDate.isBefore(lastTakenDate)) { + return 0; + } + final endDate = e.endDate; + if (endDate == null) { + return daysBetween(e.beginDate, today()); + } else if (lastTakenDate.isAfter(e.beginDate)) { + return daysBetween(e.beginDate, endDate); + } else { + return 0; + } + }).reduce((value, element) => value + element); + + return lastTakenPillNumber - summarizedRestDuration; + } bool get isAllTaken => todayPillNumber == lastTakenPillNumber; bool get isEnded => typeInfo.totalCount == lastTakenPillNumber; @@ -96,18 +152,48 @@ abstract class PillSheet implements _$PillSheet { beginingDate.date().toUtc().millisecondsSinceEpoch < now().toUtc().millisecondsSinceEpoch; bool get inNotTakenDuration => todayPillNumber > typeInfo.dosingPeriod; - bool get hasRestDuration => !pillSheetType.isNotExistsNotTakenDuration; + bool get pillSheetHasRestOrFakeDuration => + !pillSheetType.isNotExistsNotTakenDuration; bool get isActive { final n = now(); final begin = beginingDate.date(); final totalCount = typeInfo.totalCount; - final end = begin.add(Duration(days: totalCount - 1)); + final end = begin.add( + Duration(days: totalCount + summarizedRestDuration(restDurations) - 1)); return DateRange(begin, end).inRange(n); } DateTime get estimatedLastTakenDate => beginingDate .add(Duration(days: pillSheetType.totalCount - 1)) + .add(Duration(days: summarizedRestDuration(restDurations))) .date() .add(Duration(days: 1)) .subtract(Duration(seconds: 1)); + + RestDuration? get activeRestDuration { + if (restDurations.isEmpty) { + return null; + } else { + if (restDurations.last.endDate == null && + restDurations.last.beginDate.isBefore(now())) { + return restDurations.last; + } else { + return null; + } + } + } +} + +int summarizedRestDuration(List restDurations) { + if (restDurations.isEmpty) { + return 0; + } + return restDurations.map((e) { + final endDate = e.endDate; + if (endDate == null) { + return daysBetween(e.beginDate, today()); + } else { + return daysBetween(e.beginDate, endDate); + } + }).reduce((value, element) => value + element); } diff --git a/lib/entity/pill_sheet.freezed.dart b/lib/entity/pill_sheet.freezed.dart index cef2d20522..5459832439 100644 --- a/lib/entity/pill_sheet.freezed.dart +++ b/lib/entity/pill_sheet.freezed.dart @@ -245,6 +245,253 @@ abstract class _PillSheetTypeInfo implements PillSheetTypeInfo { throw _privateConstructorUsedError; } +RestDuration _$RestDurationFromJson(Map json) { + return _RestDuration.fromJson(json); +} + +/// @nodoc +class _$RestDurationTearOff { + const _$RestDurationTearOff(); + + _RestDuration call( + {@JsonKey(fromJson: NonNullTimestampConverter.timestampToDateTime, toJson: NonNullTimestampConverter.dateTimeToTimestamp) + required DateTime beginDate, + @JsonKey(fromJson: TimestampConverter.timestampToDateTime, toJson: TimestampConverter.dateTimeToTimestamp) + DateTime? endDate, + @JsonKey(fromJson: NonNullTimestampConverter.timestampToDateTime, toJson: NonNullTimestampConverter.dateTimeToTimestamp) + required DateTime createdDate}) { + return _RestDuration( + beginDate: beginDate, + endDate: endDate, + createdDate: createdDate, + ); + } + + RestDuration fromJson(Map json) { + return RestDuration.fromJson(json); + } +} + +/// @nodoc +const $RestDuration = _$RestDurationTearOff(); + +/// @nodoc +mixin _$RestDuration { + @JsonKey( + fromJson: NonNullTimestampConverter.timestampToDateTime, + toJson: NonNullTimestampConverter.dateTimeToTimestamp) + DateTime get beginDate => throw _privateConstructorUsedError; + @JsonKey( + fromJson: TimestampConverter.timestampToDateTime, + toJson: TimestampConverter.dateTimeToTimestamp) + DateTime? get endDate => throw _privateConstructorUsedError; + @JsonKey( + fromJson: NonNullTimestampConverter.timestampToDateTime, + toJson: NonNullTimestampConverter.dateTimeToTimestamp) + DateTime get createdDate => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $RestDurationCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $RestDurationCopyWith<$Res> { + factory $RestDurationCopyWith( + RestDuration value, $Res Function(RestDuration) then) = + _$RestDurationCopyWithImpl<$Res>; + $Res call( + {@JsonKey(fromJson: NonNullTimestampConverter.timestampToDateTime, toJson: NonNullTimestampConverter.dateTimeToTimestamp) + DateTime beginDate, + @JsonKey(fromJson: TimestampConverter.timestampToDateTime, toJson: TimestampConverter.dateTimeToTimestamp) + DateTime? endDate, + @JsonKey(fromJson: NonNullTimestampConverter.timestampToDateTime, toJson: NonNullTimestampConverter.dateTimeToTimestamp) + DateTime createdDate}); +} + +/// @nodoc +class _$RestDurationCopyWithImpl<$Res> implements $RestDurationCopyWith<$Res> { + _$RestDurationCopyWithImpl(this._value, this._then); + + final RestDuration _value; + // ignore: unused_field + final $Res Function(RestDuration) _then; + + @override + $Res call({ + Object? beginDate = freezed, + Object? endDate = freezed, + Object? createdDate = freezed, + }) { + return _then(_value.copyWith( + beginDate: beginDate == freezed + ? _value.beginDate + : beginDate // ignore: cast_nullable_to_non_nullable + as DateTime, + endDate: endDate == freezed + ? _value.endDate + : endDate // ignore: cast_nullable_to_non_nullable + as DateTime?, + createdDate: createdDate == freezed + ? _value.createdDate + : createdDate // ignore: cast_nullable_to_non_nullable + as DateTime, + )); + } +} + +/// @nodoc +abstract class _$RestDurationCopyWith<$Res> + implements $RestDurationCopyWith<$Res> { + factory _$RestDurationCopyWith( + _RestDuration value, $Res Function(_RestDuration) then) = + __$RestDurationCopyWithImpl<$Res>; + @override + $Res call( + {@JsonKey(fromJson: NonNullTimestampConverter.timestampToDateTime, toJson: NonNullTimestampConverter.dateTimeToTimestamp) + DateTime beginDate, + @JsonKey(fromJson: TimestampConverter.timestampToDateTime, toJson: TimestampConverter.dateTimeToTimestamp) + DateTime? endDate, + @JsonKey(fromJson: NonNullTimestampConverter.timestampToDateTime, toJson: NonNullTimestampConverter.dateTimeToTimestamp) + DateTime createdDate}); +} + +/// @nodoc +class __$RestDurationCopyWithImpl<$Res> extends _$RestDurationCopyWithImpl<$Res> + implements _$RestDurationCopyWith<$Res> { + __$RestDurationCopyWithImpl( + _RestDuration _value, $Res Function(_RestDuration) _then) + : super(_value, (v) => _then(v as _RestDuration)); + + @override + _RestDuration get _value => super._value as _RestDuration; + + @override + $Res call({ + Object? beginDate = freezed, + Object? endDate = freezed, + Object? createdDate = freezed, + }) { + return _then(_RestDuration( + beginDate: beginDate == freezed + ? _value.beginDate + : beginDate // ignore: cast_nullable_to_non_nullable + as DateTime, + endDate: endDate == freezed + ? _value.endDate + : endDate // ignore: cast_nullable_to_non_nullable + as DateTime?, + createdDate: createdDate == freezed + ? _value.createdDate + : createdDate // ignore: cast_nullable_to_non_nullable + as DateTime, + )); + } +} + +/// @nodoc + +@JsonSerializable(explicitToJson: true) +class _$_RestDuration implements _RestDuration { + _$_RestDuration( + {@JsonKey(fromJson: NonNullTimestampConverter.timestampToDateTime, toJson: NonNullTimestampConverter.dateTimeToTimestamp) + required this.beginDate, + @JsonKey(fromJson: TimestampConverter.timestampToDateTime, toJson: TimestampConverter.dateTimeToTimestamp) + this.endDate, + @JsonKey(fromJson: NonNullTimestampConverter.timestampToDateTime, toJson: NonNullTimestampConverter.dateTimeToTimestamp) + required this.createdDate}); + + factory _$_RestDuration.fromJson(Map json) => + _$_$_RestDurationFromJson(json); + + @override + @JsonKey( + fromJson: NonNullTimestampConverter.timestampToDateTime, + toJson: NonNullTimestampConverter.dateTimeToTimestamp) + final DateTime beginDate; + @override + @JsonKey( + fromJson: TimestampConverter.timestampToDateTime, + toJson: TimestampConverter.dateTimeToTimestamp) + final DateTime? endDate; + @override + @JsonKey( + fromJson: NonNullTimestampConverter.timestampToDateTime, + toJson: NonNullTimestampConverter.dateTimeToTimestamp) + final DateTime createdDate; + + @override + String toString() { + return 'RestDuration(beginDate: $beginDate, endDate: $endDate, createdDate: $createdDate)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other is _RestDuration && + (identical(other.beginDate, beginDate) || + const DeepCollectionEquality() + .equals(other.beginDate, beginDate)) && + (identical(other.endDate, endDate) || + const DeepCollectionEquality() + .equals(other.endDate, endDate)) && + (identical(other.createdDate, createdDate) || + const DeepCollectionEquality() + .equals(other.createdDate, createdDate))); + } + + @override + int get hashCode => + runtimeType.hashCode ^ + const DeepCollectionEquality().hash(beginDate) ^ + const DeepCollectionEquality().hash(endDate) ^ + const DeepCollectionEquality().hash(createdDate); + + @JsonKey(ignore: true) + @override + _$RestDurationCopyWith<_RestDuration> get copyWith => + __$RestDurationCopyWithImpl<_RestDuration>(this, _$identity); + + @override + Map toJson() { + return _$_$_RestDurationToJson(this); + } +} + +abstract class _RestDuration implements RestDuration { + factory _RestDuration( + {@JsonKey(fromJson: NonNullTimestampConverter.timestampToDateTime, toJson: NonNullTimestampConverter.dateTimeToTimestamp) + required DateTime beginDate, + @JsonKey(fromJson: TimestampConverter.timestampToDateTime, toJson: TimestampConverter.dateTimeToTimestamp) + DateTime? endDate, + @JsonKey(fromJson: NonNullTimestampConverter.timestampToDateTime, toJson: NonNullTimestampConverter.dateTimeToTimestamp) + required DateTime createdDate}) = _$_RestDuration; + + factory _RestDuration.fromJson(Map json) = + _$_RestDuration.fromJson; + + @override + @JsonKey( + fromJson: NonNullTimestampConverter.timestampToDateTime, + toJson: NonNullTimestampConverter.dateTimeToTimestamp) + DateTime get beginDate => throw _privateConstructorUsedError; + @override + @JsonKey( + fromJson: TimestampConverter.timestampToDateTime, + toJson: TimestampConverter.dateTimeToTimestamp) + DateTime? get endDate => throw _privateConstructorUsedError; + @override + @JsonKey( + fromJson: NonNullTimestampConverter.timestampToDateTime, + toJson: NonNullTimestampConverter.dateTimeToTimestamp) + DateTime get createdDate => throw _privateConstructorUsedError; + @override + @JsonKey(ignore: true) + _$RestDurationCopyWith<_RestDuration> get copyWith => + throw _privateConstructorUsedError; +} + PillSheet _$PillSheetFromJson(Map json) { return _PillSheet.fromJson(json); } @@ -266,7 +513,8 @@ class _$PillSheetTearOff { DateTime? createdAt, @JsonKey(fromJson: TimestampConverter.timestampToDateTime, toJson: TimestampConverter.dateTimeToTimestamp) DateTime? deletedAt, - int groupIndex = 0}) { + int groupIndex = 0, + List restDurations = const []}) { return _PillSheet( id: id, typeInfo: typeInfo, @@ -275,6 +523,7 @@ class _$PillSheetTearOff { createdAt: createdAt, deletedAt: deletedAt, groupIndex: groupIndex, + restDurations: restDurations, ); } @@ -309,6 +558,7 @@ mixin _$PillSheet { toJson: TimestampConverter.dateTimeToTimestamp) DateTime? get deletedAt => throw _privateConstructorUsedError; int get groupIndex => throw _privateConstructorUsedError; + List get restDurations => throw _privateConstructorUsedError; Map toJson() => throw _privateConstructorUsedError; @JsonKey(ignore: true) @@ -333,7 +583,8 @@ abstract class $PillSheetCopyWith<$Res> { DateTime? createdAt, @JsonKey(fromJson: TimestampConverter.timestampToDateTime, toJson: TimestampConverter.dateTimeToTimestamp) DateTime? deletedAt, - int groupIndex}); + int groupIndex, + List restDurations}); $PillSheetTypeInfoCopyWith<$Res> get typeInfo; } @@ -355,6 +606,7 @@ class _$PillSheetCopyWithImpl<$Res> implements $PillSheetCopyWith<$Res> { Object? createdAt = freezed, Object? deletedAt = freezed, Object? groupIndex = freezed, + Object? restDurations = freezed, }) { return _then(_value.copyWith( id: id == freezed @@ -385,6 +637,10 @@ class _$PillSheetCopyWithImpl<$Res> implements $PillSheetCopyWith<$Res> { ? _value.groupIndex : groupIndex // ignore: cast_nullable_to_non_nullable as int, + restDurations: restDurations == freezed + ? _value.restDurations + : restDurations // ignore: cast_nullable_to_non_nullable + as List, )); } @@ -415,7 +671,8 @@ abstract class _$PillSheetCopyWith<$Res> implements $PillSheetCopyWith<$Res> { DateTime? createdAt, @JsonKey(fromJson: TimestampConverter.timestampToDateTime, toJson: TimestampConverter.dateTimeToTimestamp) DateTime? deletedAt, - int groupIndex}); + int groupIndex, + List restDurations}); @override $PillSheetTypeInfoCopyWith<$Res> get typeInfo; @@ -439,6 +696,7 @@ class __$PillSheetCopyWithImpl<$Res> extends _$PillSheetCopyWithImpl<$Res> Object? createdAt = freezed, Object? deletedAt = freezed, Object? groupIndex = freezed, + Object? restDurations = freezed, }) { return _then(_PillSheet( id: id == freezed @@ -469,6 +727,10 @@ class __$PillSheetCopyWithImpl<$Res> extends _$PillSheetCopyWithImpl<$Res> ? _value.groupIndex : groupIndex // ignore: cast_nullable_to_non_nullable as int, + restDurations: restDurations == freezed + ? _value.restDurations + : restDurations // ignore: cast_nullable_to_non_nullable + as List, )); } } @@ -490,7 +752,8 @@ class _$_PillSheet extends _PillSheet { this.createdAt, @JsonKey(fromJson: TimestampConverter.timestampToDateTime, toJson: TimestampConverter.dateTimeToTimestamp) this.deletedAt, - this.groupIndex = 0}) + this.groupIndex = 0, + this.restDurations = const []}) : super._(); factory _$_PillSheet.fromJson(Map json) => @@ -525,10 +788,13 @@ class _$_PillSheet extends _PillSheet { @JsonKey(defaultValue: 0) @override final int groupIndex; + @JsonKey(defaultValue: const []) + @override + final List restDurations; @override String toString() { - return 'PillSheet(id: $id, typeInfo: $typeInfo, beginingDate: $beginingDate, lastTakenDate: $lastTakenDate, createdAt: $createdAt, deletedAt: $deletedAt, groupIndex: $groupIndex)'; + return 'PillSheet(id: $id, typeInfo: $typeInfo, beginingDate: $beginingDate, lastTakenDate: $lastTakenDate, createdAt: $createdAt, deletedAt: $deletedAt, groupIndex: $groupIndex, restDurations: $restDurations)'; } @override @@ -554,7 +820,10 @@ class _$_PillSheet extends _PillSheet { .equals(other.deletedAt, deletedAt)) && (identical(other.groupIndex, groupIndex) || const DeepCollectionEquality() - .equals(other.groupIndex, groupIndex))); + .equals(other.groupIndex, groupIndex)) && + (identical(other.restDurations, restDurations) || + const DeepCollectionEquality() + .equals(other.restDurations, restDurations))); } @override @@ -566,7 +835,8 @@ class _$_PillSheet extends _PillSheet { const DeepCollectionEquality().hash(lastTakenDate) ^ const DeepCollectionEquality().hash(createdAt) ^ const DeepCollectionEquality().hash(deletedAt) ^ - const DeepCollectionEquality().hash(groupIndex); + const DeepCollectionEquality().hash(groupIndex) ^ + const DeepCollectionEquality().hash(restDurations); @JsonKey(ignore: true) @override @@ -593,7 +863,8 @@ abstract class _PillSheet extends PillSheet { DateTime? createdAt, @JsonKey(fromJson: TimestampConverter.timestampToDateTime, toJson: TimestampConverter.dateTimeToTimestamp) DateTime? deletedAt, - int groupIndex}) = _$_PillSheet; + int groupIndex, + List restDurations}) = _$_PillSheet; _PillSheet._() : super._(); factory _PillSheet.fromJson(Map json) = @@ -628,6 +899,8 @@ abstract class _PillSheet extends PillSheet { @override int get groupIndex => throw _privateConstructorUsedError; @override + List get restDurations => throw _privateConstructorUsedError; + @override @JsonKey(ignore: true) _$PillSheetCopyWith<_PillSheet> get copyWith => throw _privateConstructorUsedError; diff --git a/lib/entity/pill_sheet.g.dart b/lib/entity/pill_sheet.g.dart index 970b0315a5..bb3f97bd92 100644 --- a/lib/entity/pill_sheet.g.dart +++ b/lib/entity/pill_sheet.g.dart @@ -24,6 +24,26 @@ Map _$_$_PillSheetTypeInfoToJson( 'dosingPeriod': instance.dosingPeriod, }; +_$_RestDuration _$_$_RestDurationFromJson(Map json) { + return _$_RestDuration( + beginDate: NonNullTimestampConverter.timestampToDateTime( + json['beginDate'] as Timestamp), + endDate: + TimestampConverter.timestampToDateTime(json['endDate'] as Timestamp?), + createdDate: NonNullTimestampConverter.timestampToDateTime( + json['createdDate'] as Timestamp), + ); +} + +Map _$_$_RestDurationToJson(_$_RestDuration instance) => + { + 'beginDate': + NonNullTimestampConverter.dateTimeToTimestamp(instance.beginDate), + 'endDate': TimestampConverter.dateTimeToTimestamp(instance.endDate), + 'createdDate': + NonNullTimestampConverter.dateTimeToTimestamp(instance.createdDate), + }; + _$_PillSheet _$_$_PillSheetFromJson(Map json) { return _$_PillSheet( id: json['id'] as String?, @@ -38,6 +58,10 @@ _$_PillSheet _$_$_PillSheetFromJson(Map json) { deletedAt: TimestampConverter.timestampToDateTime(json['deletedAt'] as Timestamp?), groupIndex: json['groupIndex'] as int? ?? 0, + restDurations: (json['restDurations'] as List?) + ?.map((e) => RestDuration.fromJson(e as Map)) + .toList() ?? + [], ); } @@ -59,5 +83,6 @@ Map _$_$_PillSheetToJson(_$_PillSheet instance) { val['createdAt'] = TimestampConverter.dateTimeToTimestamp(instance.createdAt); val['deletedAt'] = TimestampConverter.dateTimeToTimestamp(instance.deletedAt); val['groupIndex'] = instance.groupIndex; + val['restDurations'] = instance.restDurations.map((e) => e.toJson()).toList(); return val; } diff --git a/lib/entity/pill_sheet_group.dart b/lib/entity/pill_sheet_group.dart index 8f90747b8b..425fe6aaa2 100644 --- a/lib/entity/pill_sheet_group.dart +++ b/lib/entity/pill_sheet_group.dart @@ -58,72 +58,8 @@ abstract class PillSheetGroup implements _$PillSheetGroup { return copyWith(pillSheets: copied); } - int get totalPillCountIntoGroup { - return pillSheets - .map((pillSheet) => pillSheet.pillSheetType.totalCount) - .reduce((value, element) => value + element); - } - - List get passedPillSheet { - final activedPillSheet = this.activedPillSheet; - if (activedPillSheet == null) { - return pillSheets; - } - final index = pillSheets.indexOf(activedPillSheet); - final endedPillSheets = pillSheets.sublist(0, index); - return endedPillSheets; - } - - // Return null means invalid data or activedPillSheet is not found - int? get serializedTodayPillNumber { - final activedPillSheet = this.activedPillSheet; - if (activedPillSheet == null) { - return null; - } - - if (passedPillSheet.isNotEmpty) { - final passedPillCount = passedPillSheet - .map((pillSheet) => pillSheet.pillSheetType.totalCount) - .reduce((value, element) => value + element); - return passedPillCount + activedPillSheet.todayPillNumber; - } else { - // Group has only one PillSheet - return activedPillSheet.todayPillNumber; - } - } - - // Return 0 means pillSheets is empty - int get remainPillCount { - if (pillSheets.isEmpty) { - return 0; - } - return totalPillCountIntoGroup - latestTakenSerializedPillNumber; - } - - // Return null means pillSheets is empty - PillSheet? get latestTakenPillSheet { - if (pillSheets.isEmpty) { - return null; - } - return pillSheets.firstWhere((element) => - element.pillSheetType.totalCount != element.lastTakenPillNumber); - } - - // Return 0 means pillSheets is empty - int get latestTakenSerializedPillNumber { - final latestTakenPillSheet = this.latestTakenPillSheet; - if (latestTakenPillSheet == null) { - return 0; - } - if (passedPillSheet.isEmpty) { - return 0; - } - final passedPillCount = passedPillSheet - .map((pillSheet) => pillSheet.pillSheetType.totalCount) - .reduce((value, element) => value + element); - return passedPillCount + latestTakenPillSheet.lastTakenPillNumber; - } - bool get _isDeleted => deletedAt != null; bool get isDeactived => activedPillSheet == null || _isDeleted; + bool get hasPillSheetRestDuration => + pillSheets.map((e) => e.pillSheetType.hasRestDurationType).contains(true); } diff --git a/lib/entity/pill_sheet_modified_history.dart b/lib/entity/pill_sheet_modified_history.dart index 32fc79a01a..0531a38c44 100644 --- a/lib/entity/pill_sheet_modified_history.dart +++ b/lib/entity/pill_sheet_modified_history.dart @@ -26,7 +26,11 @@ enum PillSheetModifiedActionType { @JsonValue("changedPillNumber") changedPillNumber, @JsonValue("endedPillSheet") - endedPillSheet + endedPillSheet, + @JsonValue("beganRestDuration") + beganRestDuration, + @JsonValue("endedRestDuration") + endedRestDuration } extension PillSheetModifiedActionTypeFunctions on PillSheetModifiedActionType { diff --git a/lib/entity/pill_sheet_modified_history_value.dart b/lib/entity/pill_sheet_modified_history_value.dart index 98d19b82c9..b5f078dd88 100644 --- a/lib/entity/pill_sheet_modified_history_value.dart +++ b/lib/entity/pill_sheet_modified_history_value.dart @@ -1,6 +1,7 @@ import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:pilll/entity/firestore_timestamp_converter.dart'; +import 'package:pilll/entity/pill_sheet.dart'; part 'pill_sheet_modified_history_value.g.dart'; part 'pill_sheet_modified_history_value.freezed.dart'; @@ -21,6 +22,8 @@ abstract class PillSheetModifiedHistoryValue @Default(null) RevertTakenPillValue? revertTakenPill, @Default(null) ChangedPillNumberValue? changedPillNumber, @Default(null) EndedPillSheetValue? endedPillSheet, + @Default(null) BeganRestDurationValue? beganRestDurationValue, + @Default(null) EndedRestDurationValue? endedRestDurationValue, }) = _PillSheetModifiedHistoryValue; factory PillSheetModifiedHistoryValue.fromJson(Map json) => @@ -198,3 +201,31 @@ abstract class EndedPillSheetValue implements _$EndedPillSheetValue { Map toJson() => _$_$_EndedPillSheetValueToJson(this as _$_EndedPillSheetValue); } + +@freezed +abstract class BeganRestDurationValue implements _$BeganRestDurationValue { + BeganRestDurationValue._(); + @JsonSerializable(explicitToJson: true) + factory BeganRestDurationValue({ + required RestDuration restDuration, + }) = _BeganRestDurationValue; + + factory BeganRestDurationValue.fromJson(Map json) => + _$BeganRestDurationValueFromJson(json); + Map toJson() => + _$_$_BeganRestDurationValueToJson(this as _$_BeganRestDurationValue); +} + +@freezed +abstract class EndedRestDurationValue implements _$EndedRestDurationValue { + EndedRestDurationValue._(); + @JsonSerializable(explicitToJson: true) + factory EndedRestDurationValue({ + required RestDuration restDuration, + }) = _EndedRestDurationValue; + + factory EndedRestDurationValue.fromJson(Map json) => + _$EndedRestDurationValueFromJson(json); + Map toJson() => + _$_$_EndedRestDurationValueToJson(this as _$_EndedRestDurationValue); +} diff --git a/lib/entity/pill_sheet_modified_history_value.freezed.dart b/lib/entity/pill_sheet_modified_history_value.freezed.dart index 39ea76f4d3..9e927197f3 100644 --- a/lib/entity/pill_sheet_modified_history_value.freezed.dart +++ b/lib/entity/pill_sheet_modified_history_value.freezed.dart @@ -30,7 +30,9 @@ class _$PillSheetModifiedHistoryValueTearOff { TakenPillValue? takenPill = null, RevertTakenPillValue? revertTakenPill = null, ChangedPillNumberValue? changedPillNumber = null, - EndedPillSheetValue? endedPillSheet = null}) { + EndedPillSheetValue? endedPillSheet = null, + BeganRestDurationValue? beganRestDurationValue = null, + EndedRestDurationValue? endedRestDurationValue = null}) { return _PillSheetModifiedHistoryValue( beginTrialDate: beginTrialDate, createdPillSheet: createdPillSheet, @@ -40,6 +42,8 @@ class _$PillSheetModifiedHistoryValueTearOff { revertTakenPill: revertTakenPill, changedPillNumber: changedPillNumber, endedPillSheet: endedPillSheet, + beganRestDurationValue: beganRestDurationValue, + endedRestDurationValue: endedRestDurationValue, ); } @@ -67,6 +71,10 @@ mixin _$PillSheetModifiedHistoryValue { ChangedPillNumberValue? get changedPillNumber => throw _privateConstructorUsedError; EndedPillSheetValue? get endedPillSheet => throw _privateConstructorUsedError; + BeganRestDurationValue? get beganRestDurationValue => + throw _privateConstructorUsedError; + EndedRestDurationValue? get endedRestDurationValue => + throw _privateConstructorUsedError; Map toJson() => throw _privateConstructorUsedError; @JsonKey(ignore: true) @@ -89,7 +97,9 @@ abstract class $PillSheetModifiedHistoryValueCopyWith<$Res> { TakenPillValue? takenPill, RevertTakenPillValue? revertTakenPill, ChangedPillNumberValue? changedPillNumber, - EndedPillSheetValue? endedPillSheet}); + EndedPillSheetValue? endedPillSheet, + BeganRestDurationValue? beganRestDurationValue, + EndedRestDurationValue? endedRestDurationValue}); $CreatedPillSheetValueCopyWith<$Res>? get createdPillSheet; $AutomaticallyRecordedLastTakenDateValueCopyWith<$Res>? @@ -99,6 +109,8 @@ abstract class $PillSheetModifiedHistoryValueCopyWith<$Res> { $RevertTakenPillValueCopyWith<$Res>? get revertTakenPill; $ChangedPillNumberValueCopyWith<$Res>? get changedPillNumber; $EndedPillSheetValueCopyWith<$Res>? get endedPillSheet; + $BeganRestDurationValueCopyWith<$Res>? get beganRestDurationValue; + $EndedRestDurationValueCopyWith<$Res>? get endedRestDurationValue; } /// @nodoc @@ -120,6 +132,8 @@ class _$PillSheetModifiedHistoryValueCopyWithImpl<$Res> Object? revertTakenPill = freezed, Object? changedPillNumber = freezed, Object? endedPillSheet = freezed, + Object? beganRestDurationValue = freezed, + Object? endedRestDurationValue = freezed, }) { return _then(_value.copyWith( beginTrialDate: beginTrialDate == freezed @@ -155,6 +169,14 @@ class _$PillSheetModifiedHistoryValueCopyWithImpl<$Res> ? _value.endedPillSheet : endedPillSheet // ignore: cast_nullable_to_non_nullable as EndedPillSheetValue?, + beganRestDurationValue: beganRestDurationValue == freezed + ? _value.beganRestDurationValue + : beganRestDurationValue // ignore: cast_nullable_to_non_nullable + as BeganRestDurationValue?, + endedRestDurationValue: endedRestDurationValue == freezed + ? _value.endedRestDurationValue + : endedRestDurationValue // ignore: cast_nullable_to_non_nullable + as EndedRestDurationValue?, )); } @@ -240,6 +262,30 @@ class _$PillSheetModifiedHistoryValueCopyWithImpl<$Res> return _then(_value.copyWith(endedPillSheet: value)); }); } + + @override + $BeganRestDurationValueCopyWith<$Res>? get beganRestDurationValue { + if (_value.beganRestDurationValue == null) { + return null; + } + + return $BeganRestDurationValueCopyWith<$Res>(_value.beganRestDurationValue!, + (value) { + return _then(_value.copyWith(beganRestDurationValue: value)); + }); + } + + @override + $EndedRestDurationValueCopyWith<$Res>? get endedRestDurationValue { + if (_value.endedRestDurationValue == null) { + return null; + } + + return $EndedRestDurationValueCopyWith<$Res>(_value.endedRestDurationValue!, + (value) { + return _then(_value.copyWith(endedRestDurationValue: value)); + }); + } } /// @nodoc @@ -259,7 +305,9 @@ abstract class _$PillSheetModifiedHistoryValueCopyWith<$Res> TakenPillValue? takenPill, RevertTakenPillValue? revertTakenPill, ChangedPillNumberValue? changedPillNumber, - EndedPillSheetValue? endedPillSheet}); + EndedPillSheetValue? endedPillSheet, + BeganRestDurationValue? beganRestDurationValue, + EndedRestDurationValue? endedRestDurationValue}); @override $CreatedPillSheetValueCopyWith<$Res>? get createdPillSheet; @@ -276,6 +324,10 @@ abstract class _$PillSheetModifiedHistoryValueCopyWith<$Res> $ChangedPillNumberValueCopyWith<$Res>? get changedPillNumber; @override $EndedPillSheetValueCopyWith<$Res>? get endedPillSheet; + @override + $BeganRestDurationValueCopyWith<$Res>? get beganRestDurationValue; + @override + $EndedRestDurationValueCopyWith<$Res>? get endedRestDurationValue; } /// @nodoc @@ -301,6 +353,8 @@ class __$PillSheetModifiedHistoryValueCopyWithImpl<$Res> Object? revertTakenPill = freezed, Object? changedPillNumber = freezed, Object? endedPillSheet = freezed, + Object? beganRestDurationValue = freezed, + Object? endedRestDurationValue = freezed, }) { return _then(_PillSheetModifiedHistoryValue( beginTrialDate: beginTrialDate == freezed @@ -336,6 +390,14 @@ class __$PillSheetModifiedHistoryValueCopyWithImpl<$Res> ? _value.endedPillSheet : endedPillSheet // ignore: cast_nullable_to_non_nullable as EndedPillSheetValue?, + beganRestDurationValue: beganRestDurationValue == freezed + ? _value.beganRestDurationValue + : beganRestDurationValue // ignore: cast_nullable_to_non_nullable + as BeganRestDurationValue?, + endedRestDurationValue: endedRestDurationValue == freezed + ? _value.endedRestDurationValue + : endedRestDurationValue // ignore: cast_nullable_to_non_nullable + as EndedRestDurationValue?, )); } } @@ -352,7 +414,9 @@ class _$_PillSheetModifiedHistoryValue extends _PillSheetModifiedHistoryValue { this.takenPill = null, this.revertTakenPill = null, this.changedPillNumber = null, - this.endedPillSheet = null}) + this.endedPillSheet = null, + this.beganRestDurationValue = null, + this.endedRestDurationValue = null}) : super._(); factory _$_PillSheetModifiedHistoryValue.fromJson( @@ -383,10 +447,16 @@ class _$_PillSheetModifiedHistoryValue extends _PillSheetModifiedHistoryValue { @JsonKey(defaultValue: null) @override final EndedPillSheetValue? endedPillSheet; + @JsonKey(defaultValue: null) + @override + final BeganRestDurationValue? beganRestDurationValue; + @JsonKey(defaultValue: null) + @override + final EndedRestDurationValue? endedRestDurationValue; @override String toString() { - return 'PillSheetModifiedHistoryValue(beginTrialDate: $beginTrialDate, createdPillSheet: $createdPillSheet, automaticallyRecordedLastTakenDate: $automaticallyRecordedLastTakenDate, deletedPillSheet: $deletedPillSheet, takenPill: $takenPill, revertTakenPill: $revertTakenPill, changedPillNumber: $changedPillNumber, endedPillSheet: $endedPillSheet)'; + return 'PillSheetModifiedHistoryValue(beginTrialDate: $beginTrialDate, createdPillSheet: $createdPillSheet, automaticallyRecordedLastTakenDate: $automaticallyRecordedLastTakenDate, deletedPillSheet: $deletedPillSheet, takenPill: $takenPill, revertTakenPill: $revertTakenPill, changedPillNumber: $changedPillNumber, endedPillSheet: $endedPillSheet, beganRestDurationValue: $beganRestDurationValue, endedRestDurationValue: $endedRestDurationValue)'; } @override @@ -418,7 +488,13 @@ class _$_PillSheetModifiedHistoryValue extends _PillSheetModifiedHistoryValue { .equals(other.changedPillNumber, changedPillNumber)) && (identical(other.endedPillSheet, endedPillSheet) || const DeepCollectionEquality() - .equals(other.endedPillSheet, endedPillSheet))); + .equals(other.endedPillSheet, endedPillSheet)) && + (identical(other.beganRestDurationValue, beganRestDurationValue) || + const DeepCollectionEquality().equals( + other.beganRestDurationValue, beganRestDurationValue)) && + (identical(other.endedRestDurationValue, endedRestDurationValue) || + const DeepCollectionEquality().equals( + other.endedRestDurationValue, endedRestDurationValue))); } @override @@ -431,7 +507,9 @@ class _$_PillSheetModifiedHistoryValue extends _PillSheetModifiedHistoryValue { const DeepCollectionEquality().hash(takenPill) ^ const DeepCollectionEquality().hash(revertTakenPill) ^ const DeepCollectionEquality().hash(changedPillNumber) ^ - const DeepCollectionEquality().hash(endedPillSheet); + const DeepCollectionEquality().hash(endedPillSheet) ^ + const DeepCollectionEquality().hash(beganRestDurationValue) ^ + const DeepCollectionEquality().hash(endedRestDurationValue); @JsonKey(ignore: true) @override @@ -448,15 +526,18 @@ class _$_PillSheetModifiedHistoryValue extends _PillSheetModifiedHistoryValue { abstract class _PillSheetModifiedHistoryValue extends PillSheetModifiedHistoryValue { factory _PillSheetModifiedHistoryValue( - {DateTime? beginTrialDate, - CreatedPillSheetValue? createdPillSheet, - AutomaticallyRecordedLastTakenDateValue? - automaticallyRecordedLastTakenDate, - DeletedPillSheetValue? deletedPillSheet, - TakenPillValue? takenPill, - RevertTakenPillValue? revertTakenPill, - ChangedPillNumberValue? changedPillNumber, - EndedPillSheetValue? endedPillSheet}) = _$_PillSheetModifiedHistoryValue; + {DateTime? beginTrialDate, + CreatedPillSheetValue? createdPillSheet, + AutomaticallyRecordedLastTakenDateValue? + automaticallyRecordedLastTakenDate, + DeletedPillSheetValue? deletedPillSheet, + TakenPillValue? takenPill, + RevertTakenPillValue? revertTakenPill, + ChangedPillNumberValue? changedPillNumber, + EndedPillSheetValue? endedPillSheet, + BeganRestDurationValue? beganRestDurationValue, + EndedRestDurationValue? endedRestDurationValue}) = + _$_PillSheetModifiedHistoryValue; _PillSheetModifiedHistoryValue._() : super._(); factory _PillSheetModifiedHistoryValue.fromJson(Map json) = @@ -485,6 +566,12 @@ abstract class _PillSheetModifiedHistoryValue @override EndedPillSheetValue? get endedPillSheet => throw _privateConstructorUsedError; @override + BeganRestDurationValue? get beganRestDurationValue => + throw _privateConstructorUsedError; + @override + EndedRestDurationValue? get endedRestDurationValue => + throw _privateConstructorUsedError; + @override @JsonKey(ignore: true) _$PillSheetModifiedHistoryValueCopyWith<_PillSheetModifiedHistoryValue> get copyWith => throw _privateConstructorUsedError; @@ -2233,3 +2320,337 @@ abstract class _EndedPillSheetValue extends EndedPillSheetValue { _$EndedPillSheetValueCopyWith<_EndedPillSheetValue> get copyWith => throw _privateConstructorUsedError; } + +BeganRestDurationValue _$BeganRestDurationValueFromJson( + Map json) { + return _BeganRestDurationValue.fromJson(json); +} + +/// @nodoc +class _$BeganRestDurationValueTearOff { + const _$BeganRestDurationValueTearOff(); + + _BeganRestDurationValue call({required RestDuration restDuration}) { + return _BeganRestDurationValue( + restDuration: restDuration, + ); + } + + BeganRestDurationValue fromJson(Map json) { + return BeganRestDurationValue.fromJson(json); + } +} + +/// @nodoc +const $BeganRestDurationValue = _$BeganRestDurationValueTearOff(); + +/// @nodoc +mixin _$BeganRestDurationValue { + RestDuration get restDuration => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $BeganRestDurationValueCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $BeganRestDurationValueCopyWith<$Res> { + factory $BeganRestDurationValueCopyWith(BeganRestDurationValue value, + $Res Function(BeganRestDurationValue) then) = + _$BeganRestDurationValueCopyWithImpl<$Res>; + $Res call({RestDuration restDuration}); + + $RestDurationCopyWith<$Res> get restDuration; +} + +/// @nodoc +class _$BeganRestDurationValueCopyWithImpl<$Res> + implements $BeganRestDurationValueCopyWith<$Res> { + _$BeganRestDurationValueCopyWithImpl(this._value, this._then); + + final BeganRestDurationValue _value; + // ignore: unused_field + final $Res Function(BeganRestDurationValue) _then; + + @override + $Res call({ + Object? restDuration = freezed, + }) { + return _then(_value.copyWith( + restDuration: restDuration == freezed + ? _value.restDuration + : restDuration // ignore: cast_nullable_to_non_nullable + as RestDuration, + )); + } + + @override + $RestDurationCopyWith<$Res> get restDuration { + return $RestDurationCopyWith<$Res>(_value.restDuration, (value) { + return _then(_value.copyWith(restDuration: value)); + }); + } +} + +/// @nodoc +abstract class _$BeganRestDurationValueCopyWith<$Res> + implements $BeganRestDurationValueCopyWith<$Res> { + factory _$BeganRestDurationValueCopyWith(_BeganRestDurationValue value, + $Res Function(_BeganRestDurationValue) then) = + __$BeganRestDurationValueCopyWithImpl<$Res>; + @override + $Res call({RestDuration restDuration}); + + @override + $RestDurationCopyWith<$Res> get restDuration; +} + +/// @nodoc +class __$BeganRestDurationValueCopyWithImpl<$Res> + extends _$BeganRestDurationValueCopyWithImpl<$Res> + implements _$BeganRestDurationValueCopyWith<$Res> { + __$BeganRestDurationValueCopyWithImpl(_BeganRestDurationValue _value, + $Res Function(_BeganRestDurationValue) _then) + : super(_value, (v) => _then(v as _BeganRestDurationValue)); + + @override + _BeganRestDurationValue get _value => super._value as _BeganRestDurationValue; + + @override + $Res call({ + Object? restDuration = freezed, + }) { + return _then(_BeganRestDurationValue( + restDuration: restDuration == freezed + ? _value.restDuration + : restDuration // ignore: cast_nullable_to_non_nullable + as RestDuration, + )); + } +} + +/// @nodoc + +@JsonSerializable(explicitToJson: true) +class _$_BeganRestDurationValue extends _BeganRestDurationValue { + _$_BeganRestDurationValue({required this.restDuration}) : super._(); + + factory _$_BeganRestDurationValue.fromJson(Map json) => + _$_$_BeganRestDurationValueFromJson(json); + + @override + final RestDuration restDuration; + + @override + String toString() { + return 'BeganRestDurationValue(restDuration: $restDuration)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other is _BeganRestDurationValue && + (identical(other.restDuration, restDuration) || + const DeepCollectionEquality() + .equals(other.restDuration, restDuration))); + } + + @override + int get hashCode => + runtimeType.hashCode ^ const DeepCollectionEquality().hash(restDuration); + + @JsonKey(ignore: true) + @override + _$BeganRestDurationValueCopyWith<_BeganRestDurationValue> get copyWith => + __$BeganRestDurationValueCopyWithImpl<_BeganRestDurationValue>( + this, _$identity); + + @override + Map toJson() { + return _$_$_BeganRestDurationValueToJson(this); + } +} + +abstract class _BeganRestDurationValue extends BeganRestDurationValue { + factory _BeganRestDurationValue({required RestDuration restDuration}) = + _$_BeganRestDurationValue; + _BeganRestDurationValue._() : super._(); + + factory _BeganRestDurationValue.fromJson(Map json) = + _$_BeganRestDurationValue.fromJson; + + @override + RestDuration get restDuration => throw _privateConstructorUsedError; + @override + @JsonKey(ignore: true) + _$BeganRestDurationValueCopyWith<_BeganRestDurationValue> get copyWith => + throw _privateConstructorUsedError; +} + +EndedRestDurationValue _$EndedRestDurationValueFromJson( + Map json) { + return _EndedRestDurationValue.fromJson(json); +} + +/// @nodoc +class _$EndedRestDurationValueTearOff { + const _$EndedRestDurationValueTearOff(); + + _EndedRestDurationValue call({required RestDuration restDuration}) { + return _EndedRestDurationValue( + restDuration: restDuration, + ); + } + + EndedRestDurationValue fromJson(Map json) { + return EndedRestDurationValue.fromJson(json); + } +} + +/// @nodoc +const $EndedRestDurationValue = _$EndedRestDurationValueTearOff(); + +/// @nodoc +mixin _$EndedRestDurationValue { + RestDuration get restDuration => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $EndedRestDurationValueCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $EndedRestDurationValueCopyWith<$Res> { + factory $EndedRestDurationValueCopyWith(EndedRestDurationValue value, + $Res Function(EndedRestDurationValue) then) = + _$EndedRestDurationValueCopyWithImpl<$Res>; + $Res call({RestDuration restDuration}); + + $RestDurationCopyWith<$Res> get restDuration; +} + +/// @nodoc +class _$EndedRestDurationValueCopyWithImpl<$Res> + implements $EndedRestDurationValueCopyWith<$Res> { + _$EndedRestDurationValueCopyWithImpl(this._value, this._then); + + final EndedRestDurationValue _value; + // ignore: unused_field + final $Res Function(EndedRestDurationValue) _then; + + @override + $Res call({ + Object? restDuration = freezed, + }) { + return _then(_value.copyWith( + restDuration: restDuration == freezed + ? _value.restDuration + : restDuration // ignore: cast_nullable_to_non_nullable + as RestDuration, + )); + } + + @override + $RestDurationCopyWith<$Res> get restDuration { + return $RestDurationCopyWith<$Res>(_value.restDuration, (value) { + return _then(_value.copyWith(restDuration: value)); + }); + } +} + +/// @nodoc +abstract class _$EndedRestDurationValueCopyWith<$Res> + implements $EndedRestDurationValueCopyWith<$Res> { + factory _$EndedRestDurationValueCopyWith(_EndedRestDurationValue value, + $Res Function(_EndedRestDurationValue) then) = + __$EndedRestDurationValueCopyWithImpl<$Res>; + @override + $Res call({RestDuration restDuration}); + + @override + $RestDurationCopyWith<$Res> get restDuration; +} + +/// @nodoc +class __$EndedRestDurationValueCopyWithImpl<$Res> + extends _$EndedRestDurationValueCopyWithImpl<$Res> + implements _$EndedRestDurationValueCopyWith<$Res> { + __$EndedRestDurationValueCopyWithImpl(_EndedRestDurationValue _value, + $Res Function(_EndedRestDurationValue) _then) + : super(_value, (v) => _then(v as _EndedRestDurationValue)); + + @override + _EndedRestDurationValue get _value => super._value as _EndedRestDurationValue; + + @override + $Res call({ + Object? restDuration = freezed, + }) { + return _then(_EndedRestDurationValue( + restDuration: restDuration == freezed + ? _value.restDuration + : restDuration // ignore: cast_nullable_to_non_nullable + as RestDuration, + )); + } +} + +/// @nodoc + +@JsonSerializable(explicitToJson: true) +class _$_EndedRestDurationValue extends _EndedRestDurationValue { + _$_EndedRestDurationValue({required this.restDuration}) : super._(); + + factory _$_EndedRestDurationValue.fromJson(Map json) => + _$_$_EndedRestDurationValueFromJson(json); + + @override + final RestDuration restDuration; + + @override + String toString() { + return 'EndedRestDurationValue(restDuration: $restDuration)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other is _EndedRestDurationValue && + (identical(other.restDuration, restDuration) || + const DeepCollectionEquality() + .equals(other.restDuration, restDuration))); + } + + @override + int get hashCode => + runtimeType.hashCode ^ const DeepCollectionEquality().hash(restDuration); + + @JsonKey(ignore: true) + @override + _$EndedRestDurationValueCopyWith<_EndedRestDurationValue> get copyWith => + __$EndedRestDurationValueCopyWithImpl<_EndedRestDurationValue>( + this, _$identity); + + @override + Map toJson() { + return _$_$_EndedRestDurationValueToJson(this); + } +} + +abstract class _EndedRestDurationValue extends EndedRestDurationValue { + factory _EndedRestDurationValue({required RestDuration restDuration}) = + _$_EndedRestDurationValue; + _EndedRestDurationValue._() : super._(); + + factory _EndedRestDurationValue.fromJson(Map json) = + _$_EndedRestDurationValue.fromJson; + + @override + RestDuration get restDuration => throw _privateConstructorUsedError; + @override + @JsonKey(ignore: true) + _$EndedRestDurationValueCopyWith<_EndedRestDurationValue> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/entity/pill_sheet_modified_history_value.g.dart b/lib/entity/pill_sheet_modified_history_value.g.dart index 29c21628b1..93b9149c09 100644 --- a/lib/entity/pill_sheet_modified_history_value.g.dart +++ b/lib/entity/pill_sheet_modified_history_value.g.dart @@ -41,6 +41,14 @@ _$_PillSheetModifiedHistoryValue _$_$_PillSheetModifiedHistoryValueFromJson( ? null : EndedPillSheetValue.fromJson( json['endedPillSheet'] as Map), + beganRestDurationValue: json['beganRestDurationValue'] == null + ? null + : BeganRestDurationValue.fromJson( + json['beganRestDurationValue'] as Map), + endedRestDurationValue: json['endedRestDurationValue'] == null + ? null + : EndedRestDurationValue.fromJson( + json['endedRestDurationValue'] as Map), ); } @@ -56,6 +64,8 @@ Map _$_$_PillSheetModifiedHistoryValueToJson( 'revertTakenPill': instance.revertTakenPill?.toJson(), 'changedPillNumber': instance.changedPillNumber?.toJson(), 'endedPillSheet': instance.endedPillSheet?.toJson(), + 'beganRestDurationValue': instance.beganRestDurationValue?.toJson(), + 'endedRestDurationValue': instance.endedRestDurationValue?.toJson(), }; _$_CreatedPillSheetValue _$_$_CreatedPillSheetValueFromJson( @@ -211,3 +221,31 @@ Map _$_$_EndedPillSheetValueToJson( 'lastTakenDate': NonNullTimestampConverter.dateTimeToTimestamp(instance.lastTakenDate), }; + +_$_BeganRestDurationValue _$_$_BeganRestDurationValueFromJson( + Map json) { + return _$_BeganRestDurationValue( + restDuration: + RestDuration.fromJson(json['restDuration'] as Map), + ); +} + +Map _$_$_BeganRestDurationValueToJson( + _$_BeganRestDurationValue instance) => + { + 'restDuration': instance.restDuration.toJson(), + }; + +_$_EndedRestDurationValue _$_$_EndedRestDurationValueFromJson( + Map json) { + return _$_EndedRestDurationValue( + restDuration: + RestDuration.fromJson(json['restDuration'] as Map), + ); +} + +Map _$_$_EndedRestDurationValueToJson( + _$_EndedRestDurationValue instance) => + { + 'restDuration': instance.restDuration.toJson(), + }; diff --git a/lib/entity/pill_sheet_type.dart b/lib/entity/pill_sheet_type.dart index f52db69939..6c91f67669 100644 --- a/lib/entity/pill_sheet_type.dart +++ b/lib/entity/pill_sheet_type.dart @@ -161,11 +161,28 @@ extension PillSheetTypeFunctions on PillSheetType { } } + bool get hasRestDurationType { + switch (this) { + case PillSheetType.pillsheet_21: + return true; + case PillSheetType.pillsheet_28_4: + return false; + case PillSheetType.pillsheet_28_7: + return false; + case PillSheetType.pillsheet_28_0: + return false; + case PillSheetType.pillsheet_24_0: + return false; + case PillSheetType.pillsheet_21_0: + return false; + } + } + int get numberOfLineInPillSheet => (totalCount / Weekday.values.length).ceil(); } -int passedTotalCount( +int summarizedPillSheetTypeTotalCountToPageIndex( {required List pillSheetTypes, required int pageIndex}) { if (pageIndex == 0) { return 0; diff --git a/lib/service/pill_sheet_modified_history.dart b/lib/service/pill_sheet_modified_history.dart index cb62b02fc4..708a553c3a 100644 --- a/lib/service/pill_sheet_modified_history.dart +++ b/lib/service/pill_sheet_modified_history.dart @@ -243,4 +243,50 @@ extension PillSheetModifiedHistoryServiceActionFactory after: null, ); } + + static PillSheetModifiedHistory createBeganRestDurationAction({ + required String? pillSheetGroupID, + required PillSheet before, + required PillSheet after, + required RestDuration restDuration, + }) { + assert(pillSheetGroupID != null); + + return _create( + actionType: PillSheetModifiedActionType.beganRestDuration, + value: PillSheetModifiedHistoryValue( + beganRestDurationValue: BeganRestDurationValue( + restDuration: restDuration, + ), + ), + pillSheetGroupID: pillSheetGroupID, + beforePillSheetID: before.id, + afterPillSheetID: after.id, + before: before, + after: after, + ); + } + + static PillSheetModifiedHistory createEndedRestDurationAction({ + required String? pillSheetGroupID, + required PillSheet before, + required PillSheet after, + required RestDuration restDuration, + }) { + assert(pillSheetGroupID != null); + + return _create( + actionType: PillSheetModifiedActionType.endedRestDuration, + value: PillSheetModifiedHistoryValue( + endedRestDurationValue: EndedRestDurationValue( + restDuration: restDuration, + ), + ), + pillSheetGroupID: pillSheetGroupID, + beforePillSheetID: before.id, + afterPillSheetID: after.id, + before: before, + after: after, + ); + } } diff --git a/lib/util/datetime/day.dart b/lib/util/datetime/day.dart index a522bda32d..ca21c1c6ce 100644 --- a/lib/util/datetime/day.dart +++ b/lib/util/datetime/day.dart @@ -24,3 +24,10 @@ extension Date on DateTime { return DateTime(year, month, day); } } + +// Reference: https://stackoverflow.com/questions/52713115/flutter-find-the-number-of-days-between-two-dates/67679455#67679455 +int daysBetween(DateTime from, DateTime to) { + from = DateTime(from.year, from.month, from.day); + to = DateTime(to.year, to.month, to.day); + return (to.difference(from).inHours / 24).round(); +} diff --git a/test/domain/record/components/record_page_pill_sheet_test.dart b/test/domain/record/components/record_page_pill_sheet_test.dart index 7b40e741d9..fe9054cf81 100644 --- a/test/domain/record/components/record_page_pill_sheet_test.dart +++ b/test/domain/record/components/record_page_pill_sheet_test.dart @@ -1,16 +1,291 @@ +import 'package:mockito/mockito.dart'; import 'package:pilll/domain/record/components/pill_sheet/record_page_pill_sheet.dart'; import 'package:pilll/entity/pill_sheet.dart'; import 'package:pilll/entity/pill_sheet_group.dart'; import 'package:pilll/entity/pill_sheet_type.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:pilll/entity/setting.dart'; +import 'package:pilll/service/day.dart'; import 'package:shared_preferences/shared_preferences.dart'; +import '../../../helper/mock.mocks.dart'; + void main() { setUp(() { TestWidgetsFlutterBinding.ensureInitialized(); SharedPreferences.setMockInitialValues({}); }); + group("#RecordPagePillSheet.calculatedDateOfAppearancePill", () { + test("it is not have rest duration", () { + final originalTodayRepository = todayRepository; + final mockTodayRepository = MockTodayService(); + todayRepository = mockTodayRepository; + when(mockTodayRepository.now()).thenReturn(DateTime.parse("2020-09-01")); + when(mockTodayRepository.today()) + .thenReturn(DateTime.parse("2020-09-01")); + addTearDown(() { + todayRepository = originalTodayRepository; + }); + + final PillSheet pillSheet = PillSheet( + typeInfo: PillSheetType.pillsheet_21_0.typeInfo, + beginingDate: DateTime.parse("2020-09-01")); + + expect(RecordPagePillSheet.calculatedDateOfAppearancePill(pillSheet, 1), + DateTime.parse("2020-09-01")); + expect(RecordPagePillSheet.calculatedDateOfAppearancePill(pillSheet, 2), + DateTime.parse("2020-09-02")); + expect(RecordPagePillSheet.calculatedDateOfAppearancePill(pillSheet, 3), + DateTime.parse("2020-09-03")); + + expect(RecordPagePillSheet.calculatedDateOfAppearancePill(pillSheet, 10), + DateTime.parse("2020-09-10")); + expect(RecordPagePillSheet.calculatedDateOfAppearancePill(pillSheet, 11), + DateTime.parse("2020-09-11")); + expect(RecordPagePillSheet.calculatedDateOfAppearancePill(pillSheet, 12), + DateTime.parse("2020-09-12")); + + expect(RecordPagePillSheet.calculatedDateOfAppearancePill(pillSheet, 26), + DateTime.parse("2020-09-26")); + expect(RecordPagePillSheet.calculatedDateOfAppearancePill(pillSheet, 27), + DateTime.parse("2020-09-27")); + expect(RecordPagePillSheet.calculatedDateOfAppearancePill(pillSheet, 28), + DateTime.parse("2020-09-28")); + }); + group("it is have rest duration", () { + group("it is not ended rest duration", () { + test( + "simualte begin rest duration. pillSheet.lastTakenDate is yesterday and restDuration.beginDate is today.", + () { + final originalTodayRepository = todayRepository; + final mockTodayRepository = MockTodayService(); + todayRepository = mockTodayRepository; + when(mockTodayRepository.now()) + .thenReturn(DateTime.parse("2020-09-11")); + when(mockTodayRepository.today()) + .thenReturn(DateTime.parse("2020-09-11")); + addTearDown(() { + todayRepository = originalTodayRepository; + }); + + final PillSheet pillSheet = PillSheet( + typeInfo: PillSheetType.pillsheet_21_0.typeInfo, + beginingDate: DateTime.parse("2020-09-01"), + lastTakenDate: DateTime.parse("2020-09-10"), + restDurations: [ + RestDuration( + beginDate: DateTime.parse("2020-09-11"), + createdDate: DateTime.parse("2020-09-11"), + ), + ], + ); + + expect( + RecordPagePillSheet.calculatedDateOfAppearancePill(pillSheet, 1), + DateTime.parse("2020-09-01")); + expect( + RecordPagePillSheet.calculatedDateOfAppearancePill(pillSheet, 2), + DateTime.parse("2020-09-02")); + expect( + RecordPagePillSheet.calculatedDateOfAppearancePill(pillSheet, 3), + DateTime.parse("2020-09-03")); + + expect( + RecordPagePillSheet.calculatedDateOfAppearancePill(pillSheet, 10), + DateTime.parse("2020-09-10")); + expect( + RecordPagePillSheet.calculatedDateOfAppearancePill(pillSheet, 11), + DateTime.parse("2020-09-11")); + expect( + RecordPagePillSheet.calculatedDateOfAppearancePill(pillSheet, 12), + DateTime.parse("2020-09-12")); + + expect( + RecordPagePillSheet.calculatedDateOfAppearancePill(pillSheet, 26), + DateTime.parse("2020-09-26")); + expect( + RecordPagePillSheet.calculatedDateOfAppearancePill(pillSheet, 27), + DateTime.parse("2020-09-27")); + expect( + RecordPagePillSheet.calculatedDateOfAppearancePill(pillSheet, 28), + DateTime.parse("2020-09-28")); + }); + test( + "pillSheet.lastTakenDate is two days ago and restDuration.beginDate from yesterday", + () { + final originalTodayRepository = todayRepository; + final mockTodayRepository = MockTodayService(); + todayRepository = mockTodayRepository; + when(mockTodayRepository.now()) + .thenReturn(DateTime.parse("2020-09-12")); + when(mockTodayRepository.today()) + .thenReturn(DateTime.parse("2020-09-12")); + addTearDown(() { + todayRepository = originalTodayRepository; + }); + + final PillSheet pillSheet = PillSheet( + typeInfo: PillSheetType.pillsheet_21_0.typeInfo, + beginingDate: DateTime.parse("2020-09-01"), + lastTakenDate: DateTime.parse("2020-09-10"), + restDurations: [ + RestDuration( + beginDate: DateTime.parse("2020-09-11"), + createdDate: DateTime.parse("2020-09-11"), + ), + ], + ); + + expect( + RecordPagePillSheet.calculatedDateOfAppearancePill(pillSheet, 1), + DateTime.parse("2020-09-01")); + expect( + RecordPagePillSheet.calculatedDateOfAppearancePill(pillSheet, 2), + DateTime.parse("2020-09-02")); + expect( + RecordPagePillSheet.calculatedDateOfAppearancePill(pillSheet, 3), + DateTime.parse("2020-09-03")); + + expect( + RecordPagePillSheet.calculatedDateOfAppearancePill(pillSheet, 10), + DateTime.parse("2020-09-10")); + expect( + RecordPagePillSheet.calculatedDateOfAppearancePill(pillSheet, 11), + DateTime.parse("2020-09-12")); + expect( + RecordPagePillSheet.calculatedDateOfAppearancePill(pillSheet, 12), + DateTime.parse("2020-09-13")); + + expect( + RecordPagePillSheet.calculatedDateOfAppearancePill(pillSheet, 26), + DateTime.parse("2020-09-27")); + expect( + RecordPagePillSheet.calculatedDateOfAppearancePill(pillSheet, 27), + DateTime.parse("2020-09-28")); + expect( + RecordPagePillSheet.calculatedDateOfAppearancePill(pillSheet, 28), + DateTime.parse("2020-09-29")); + }); + }); + group("it is ended rest duration", () { + test( + "pillSheet.lastTakenDate is yesterday and restDuration.endDate is today", + () { + final originalTodayRepository = todayRepository; + final mockTodayRepository = MockTodayService(); + todayRepository = mockTodayRepository; + when(mockTodayRepository.now()) + .thenReturn(DateTime.parse("2020-09-11")); + when(mockTodayRepository.today()) + .thenReturn(DateTime.parse("2020-09-11")); + addTearDown(() { + todayRepository = originalTodayRepository; + }); + + final PillSheet pillSheet = PillSheet( + typeInfo: PillSheetType.pillsheet_21_0.typeInfo, + beginingDate: DateTime.parse("2020-09-01"), + lastTakenDate: DateTime.parse("2020-09-10"), + restDurations: [ + RestDuration( + beginDate: DateTime.parse("2020-09-11"), + createdDate: DateTime.parse("2020-09-11"), + endDate: DateTime.parse("2020-09-11"), + ), + ], + ); + + expect( + RecordPagePillSheet.calculatedDateOfAppearancePill(pillSheet, 1), + DateTime.parse("2020-09-01")); + expect( + RecordPagePillSheet.calculatedDateOfAppearancePill(pillSheet, 2), + DateTime.parse("2020-09-02")); + expect( + RecordPagePillSheet.calculatedDateOfAppearancePill(pillSheet, 3), + DateTime.parse("2020-09-03")); + + expect( + RecordPagePillSheet.calculatedDateOfAppearancePill(pillSheet, 10), + DateTime.parse("2020-09-10")); + expect( + RecordPagePillSheet.calculatedDateOfAppearancePill(pillSheet, 11), + DateTime.parse("2020-09-11")); + expect( + RecordPagePillSheet.calculatedDateOfAppearancePill(pillSheet, 12), + DateTime.parse("2020-09-12")); + + expect( + RecordPagePillSheet.calculatedDateOfAppearancePill(pillSheet, 26), + DateTime.parse("2020-09-26")); + expect( + RecordPagePillSheet.calculatedDateOfAppearancePill(pillSheet, 27), + DateTime.parse("2020-09-27")); + expect( + RecordPagePillSheet.calculatedDateOfAppearancePill(pillSheet, 28), + DateTime.parse("2020-09-28")); + }); + + test( + "pillSheet.lastTakenDate is two days ago and restDuration.endDate is today", + () { + final originalTodayRepository = todayRepository; + final mockTodayRepository = MockTodayService(); + todayRepository = mockTodayRepository; + when(mockTodayRepository.now()) + .thenReturn(DateTime.parse("2020-09-12")); + when(mockTodayRepository.today()) + .thenReturn(DateTime.parse("2020-09-12")); + addTearDown(() { + todayRepository = originalTodayRepository; + }); + + final PillSheet pillSheet = PillSheet( + typeInfo: PillSheetType.pillsheet_21_0.typeInfo, + beginingDate: DateTime.parse("2020-09-01"), + lastTakenDate: DateTime.parse("2020-09-10"), + restDurations: [ + RestDuration( + beginDate: DateTime.parse("2020-09-11"), + createdDate: DateTime.parse("2020-09-11"), + endDate: DateTime.parse("2020-09-12"), + ), + ], + ); + + expect( + RecordPagePillSheet.calculatedDateOfAppearancePill(pillSheet, 1), + DateTime.parse("2020-09-01")); + expect( + RecordPagePillSheet.calculatedDateOfAppearancePill(pillSheet, 2), + DateTime.parse("2020-09-02")); + expect( + RecordPagePillSheet.calculatedDateOfAppearancePill(pillSheet, 3), + DateTime.parse("2020-09-03")); + + expect( + RecordPagePillSheet.calculatedDateOfAppearancePill(pillSheet, 10), + DateTime.parse("2020-09-10")); + expect( + RecordPagePillSheet.calculatedDateOfAppearancePill(pillSheet, 11), + DateTime.parse("2020-09-12")); + expect( + RecordPagePillSheet.calculatedDateOfAppearancePill(pillSheet, 12), + DateTime.parse("2020-09-13")); + + expect( + RecordPagePillSheet.calculatedDateOfAppearancePill(pillSheet, 26), + DateTime.parse("2020-09-27")); + expect( + RecordPagePillSheet.calculatedDateOfAppearancePill(pillSheet, 27), + DateTime.parse("2020-09-28")); + expect( + RecordPagePillSheet.calculatedDateOfAppearancePill(pillSheet, 28), + DateTime.parse("2020-09-29")); + }); + }); + }); + }); group("#RecordPagePillSheet.isContainedMenstruationDuration", () { test("group has only one pill sheet", () async { final anyDate = DateTime.parse("2020-09-19"); diff --git a/test/domain/settings/components/today_pill_number/setting_today_pill_number_store_test.dart b/test/domain/settings/components/today_pill_number/setting_today_pill_number_store_test.dart index 6521d9ce0a..343197c4c2 100644 --- a/test/domain/settings/components/today_pill_number/setting_today_pill_number_store_test.dart +++ b/test/domain/settings/components/today_pill_number/setting_today_pill_number_store_test.dart @@ -509,4 +509,121 @@ void main() { ); }); }); + group("pill sheet has rest durations", () { + test( + "group has three pill sheet and it is changed direction middle to left", + () async { + var mockTodayRepository = MockTodayService(); + final _today = DateTime.parse("2022-05-02"); + todayRepository = mockTodayRepository; + when(mockTodayRepository.today()).thenReturn(_today); + when(mockTodayRepository.now()).thenReturn(_today); + + final batchFactory = MockBatchFactory(); + final batch = MockWriteBatch(); + when(batchFactory.batch()).thenReturn(batch); + final left = PillSheet( + id: "sheet_id_left", + typeInfo: PillSheetType.pillsheet_28_0.typeInfo, + beginingDate: DateTime.parse("2022-04-03"), + groupIndex: 0, + lastTakenDate: DateTime.parse("2022-04-30"), + restDurations: [ + RestDuration( + beginDate: DateTime.parse("2022-04-03"), + createdDate: DateTime.parse("2022-04-03"), + endDate: DateTime.parse("2022-04-04"), + ), + ], + ); + final middle = PillSheet( + id: "sheet_id_middle", + typeInfo: PillSheetType.pillsheet_28_0.typeInfo, + beginingDate: DateTime.parse("2022-05-02"), + groupIndex: 1, + lastTakenDate: null, + ); + final right = PillSheet( + id: "sheet_id_right", + typeInfo: PillSheetType.pillsheet_28_0.typeInfo, + beginingDate: DateTime.parse("2022-05-29"), + groupIndex: 2, + lastTakenDate: null, + ); + final updatedLeft = left.copyWith( + beginingDate: DateTime.parse("2022-04-05"), + lastTakenDate: DateTime.parse("2022-05-01"), // todayPillNumber - 1 + restDurations: [], + ); + final updatedMiddle = middle.copyWith( + beginingDate: DateTime.parse("2022-05-03"), + ); + final updatedRight = right.copyWith( + beginingDate: DateTime.parse("2022-05-31"), + ); + final pillSheetService = MockPillSheetService(); + when(pillSheetService.update(batch, [ + updatedLeft, + updatedMiddle, + updatedRight, + ])).thenReturn(null); + + final pillSheetGroup = PillSheetGroup( + id: "group_id", + pillSheetIDs: ["sheet_id_left", "sheet_id_middle", "sheet_id_right"], + pillSheets: [ + left, + middle, + right, + ], + createdAt: now(), + ); + final updatedPillSheetGroup = pillSheetGroup.copyWith(pillSheets: [ + updatedLeft, + updatedMiddle, + updatedRight, + ]); + final pillSheetGroupService = MockPillSheetGroupService(); + when(pillSheetGroupService.update(batch, updatedPillSheetGroup)) + .thenReturn(updatedPillSheetGroup); + + final history = PillSheetModifiedHistoryServiceActionFactory + .createChangedPillNumberAction( + pillSheetGroupID: "group_id", + before: middle, + after: updatedLeft, + ); + + final pillSheetModifiedHistoryService = + MockPillSheetModifiedHistoryService(); + when(pillSheetModifiedHistoryService.add(batch, history)) + .thenReturn(null); + + final container = ProviderContainer( + overrides: [ + batchFactoryProvider.overrideWithValue(batchFactory), + pillSheetServiceProvider.overrideWithValue(pillSheetService), + pillSheetModifiedHistoryServiceProvider + .overrideWithValue(pillSheetModifiedHistoryService), + pillSheetGroupServiceProvider + .overrideWithValue(pillSheetGroupService), + ], + ); + final parameter = SettingTodayPillNumberStoreParameter( + pillSheetGroup: pillSheetGroup, activedPillSheet: middle); + final store = + container.read(settingTodayPillNumberStoreProvider(parameter)); + + expect(middle.todayPillNumber, 1); + + store.markSelected( + pageIndex: 0, + pillNumberIntoPillSheet: 28, + ); + await store.modifiyTodayPillNumber( + pillSheetGroup: pillSheetGroup, + activedPillSheet: pillSheetGroup.activedPillSheet!, + ); + }); + }); } diff --git a/test/entity/pill_sheet_test.dart b/test/entity/pill_sheet_test.dart index 529687f2c6..08734e4bae 100644 --- a/test/entity/pill_sheet_test.dart +++ b/test/entity/pill_sheet_test.dart @@ -14,13 +14,13 @@ void main() { }); group("#todayPillNumber", () { test("today: 2020-09-19, begin: 2020-09-14, end: 2020-09-18", () { - var mockTodayRepository = MockTodayService(); + final mockTodayRepository = MockTodayService(); todayRepository = mockTodayRepository; when(mockTodayRepository.today()) .thenReturn(DateTime.parse("2020-09-19")); - var sheetType = PillSheetType.pillsheet_21; - var model = PillSheet( + final sheetType = PillSheetType.pillsheet_21; + final model = PillSheet( beginingDate: DateTime.parse("2020-09-14"), lastTakenDate: DateTime.parse("2020-09-18"), typeInfo: PillSheetTypeInfo( @@ -33,13 +33,13 @@ void main() { expect(model.todayPillNumber, 6); }); test("today: 2020-09-28, begin: 2020-09-01, end: 2020-09-28", () { - var mockTodayRepository = MockTodayService(); + final mockTodayRepository = MockTodayService(); todayRepository = mockTodayRepository; when(mockTodayRepository.today()) .thenReturn(DateTime.parse("2020-09-28")); - var sheetType = PillSheetType.pillsheet_21; - var model = PillSheet( + final sheetType = PillSheetType.pillsheet_21; + final model = PillSheet( beginingDate: DateTime.parse("2020-09-01"), lastTakenDate: DateTime.parse("2020-09-28"), typeInfo: PillSheetTypeInfo( @@ -51,15 +51,132 @@ void main() { ); expect(model.todayPillNumber, 28); }); + group("pillsheet has rest durations", () { + test("rest duration is not end", () { + final mockTodayRepository = MockTodayService(); + todayRepository = mockTodayRepository; + when(mockTodayRepository.today()) + .thenReturn(DateTime.parse("2020-09-28")); + + final sheetType = PillSheetType.pillsheet_21; + final model = PillSheet( + beginingDate: DateTime.parse("2020-09-01"), + lastTakenDate: DateTime.parse("2020-09-28"), + restDurations: [ + RestDuration( + beginDate: DateTime.parse("2020-09-22"), + createdDate: DateTime.parse("2020-09-22"), + ) + ], + typeInfo: PillSheetTypeInfo( + dosingPeriod: sheetType.dosingPeriod, + name: sheetType.fullName, + totalCount: sheetType.totalCount, + pillSheetTypeReferencePath: sheetType.rawPath, + ), + ); + expect(model.todayPillNumber, 22); + }); + + test("rest duration is ended", () { + final mockTodayRepository = MockTodayService(); + todayRepository = mockTodayRepository; + when(mockTodayRepository.today()) + .thenReturn(DateTime.parse("2020-09-28")); + + final sheetType = PillSheetType.pillsheet_21; + final model = PillSheet( + beginingDate: DateTime.parse("2020-09-01"), + lastTakenDate: DateTime.parse("2020-09-28"), + restDurations: [ + RestDuration( + beginDate: DateTime.parse("2020-09-22"), + createdDate: DateTime.parse("2020-09-22"), + endDate: DateTime.parse("2020-09-25"), + ) + ], + typeInfo: PillSheetTypeInfo( + dosingPeriod: sheetType.dosingPeriod, + name: sheetType.fullName, + totalCount: sheetType.totalCount, + pillSheetTypeReferencePath: sheetType.rawPath, + ), + ); + expect(model.todayPillNumber, 25); + }); + group("rest duration has plural rest duration. ", () { + test("last rest duration is not ended", () { + final mockTodayRepository = MockTodayService(); + todayRepository = mockTodayRepository; + when(mockTodayRepository.today()) + .thenReturn(DateTime.parse("2020-09-28")); + + final sheetType = PillSheetType.pillsheet_21; + final model = PillSheet( + beginingDate: DateTime.parse("2020-09-01"), + lastTakenDate: DateTime.parse("2020-09-28"), + restDurations: [ + RestDuration( + beginDate: DateTime.parse("2020-09-12"), + createdDate: DateTime.parse("2020-09-12"), + endDate: DateTime.parse("2020-09-15"), + ), + RestDuration( + beginDate: DateTime.parse("2020-09-22"), + createdDate: DateTime.parse("2020-09-22"), + ) + ], + typeInfo: PillSheetTypeInfo( + dosingPeriod: sheetType.dosingPeriod, + name: sheetType.fullName, + totalCount: sheetType.totalCount, + pillSheetTypeReferencePath: sheetType.rawPath, + ), + ); + expect(model.todayPillNumber, 19); + }); + test("last rest duration is ended", () { + final mockTodayRepository = MockTodayService(); + todayRepository = mockTodayRepository; + when(mockTodayRepository.today()) + .thenReturn(DateTime.parse("2020-09-28")); + + final sheetType = PillSheetType.pillsheet_21; + final model = PillSheet( + beginingDate: DateTime.parse("2020-09-01"), + lastTakenDate: DateTime.parse("2020-09-28"), + restDurations: [ + RestDuration( + beginDate: DateTime.parse("2020-09-12"), + createdDate: DateTime.parse("2020-09-12"), + endDate: DateTime.parse("2020-09-15"), + ), + RestDuration( + beginDate: DateTime.parse("2020-09-22"), + createdDate: DateTime.parse("2020-09-22"), + endDate: DateTime.parse("2020-09-25"), + ) + ], + typeInfo: PillSheetTypeInfo( + dosingPeriod: sheetType.dosingPeriod, + name: sheetType.fullName, + totalCount: sheetType.totalCount, + pillSheetTypeReferencePath: sheetType.rawPath, + ), + ); + expect(model.todayPillNumber, 22); + }); + }); + }); }); group("#isActive", () { test("it is active pattern. today: 2020-09-19, begin: 2020-09-14", () { - var mockTodayRepository = MockTodayService(); + final mockTodayRepository = MockTodayService(); todayRepository = mockTodayRepository; when(mockTodayRepository.now()).thenReturn(DateTime.parse("2020-09-19")); - var sheetType = PillSheetType.pillsheet_21; - var model = PillSheet( + final sheetType = PillSheetType.pillsheet_21; + final model = PillSheet( beginingDate: DateTime.parse("2020-09-14"), typeInfo: PillSheetTypeInfo( dosingPeriod: sheetType.dosingPeriod, @@ -73,12 +190,12 @@ void main() { test( "it is active pattern. Boundary testing. today: 2020-09-28, begin: 2020-09-01", () { - var mockTodayRepository = MockTodayService(); + final mockTodayRepository = MockTodayService(); todayRepository = mockTodayRepository; when(mockTodayRepository.now()).thenReturn(DateTime.parse("2020-09-28")); - var sheetType = PillSheetType.pillsheet_21; - var model = PillSheet( + final sheetType = PillSheetType.pillsheet_21; + final model = PillSheet( beginingDate: DateTime.parse("2020-09-01"), typeInfo: PillSheetTypeInfo( dosingPeriod: sheetType.dosingPeriod, @@ -92,12 +209,12 @@ void main() { test( "it is deactive pattern. Boundary testing. today: 2020-09-29, begin: 2020-09-01", () { - var mockTodayRepository = MockTodayService(); + final mockTodayRepository = MockTodayService(); todayRepository = mockTodayRepository; when(mockTodayRepository.now()).thenReturn(DateTime.parse("2020-09-29")); - var sheetType = PillSheetType.pillsheet_21; - var model = PillSheet( + final sheetType = PillSheetType.pillsheet_21; + final model = PillSheet( beginingDate: DateTime.parse("2020-09-01"), typeInfo: PillSheetTypeInfo( dosingPeriod: sheetType.dosingPeriod, @@ -111,13 +228,63 @@ void main() { test( "it is active pattern. Boundary testing. now: 2020-09-28 23:59:59, begin: 2020-09-01", () { - var mockTodayRepository = MockTodayService(); + final mockTodayRepository = MockTodayService(); todayRepository = mockTodayRepository; when(mockTodayRepository.now()) .thenReturn(DateTime(2020, 9, 28, 23, 59, 59)); - var sheetType = PillSheetType.pillsheet_21; - var model = PillSheet( + final sheetType = PillSheetType.pillsheet_21; + final model = PillSheet( + beginingDate: DateTime.parse("2020-09-01"), + typeInfo: PillSheetTypeInfo( + dosingPeriod: sheetType.dosingPeriod, + name: sheetType.fullName, + totalCount: sheetType.totalCount, + pillSheetTypeReferencePath: sheetType.rawPath, + ), + ); + expect(model.isActive, true); + }); + test( + "it is active pattern. for avoid out of active duration when during rest duration", + () { + final mockTodayRepository = MockTodayService(); + todayRepository = mockTodayRepository; + when(mockTodayRepository.now()) + .thenReturn(DateTime(2020, 9, 29, 23, 59, 59)); + when(mockTodayRepository.today()) + .thenReturn(DateTime.parse("2020-09-29")); + + final sheetType = PillSheetType.pillsheet_21; + final model = PillSheet( + beginingDate: DateTime.parse("2020-09-01"), + typeInfo: PillSheetTypeInfo( + dosingPeriod: sheetType.dosingPeriod, + name: sheetType.fullName, + totalCount: sheetType.totalCount, + pillSheetTypeReferencePath: sheetType.rawPath, + ), + restDurations: [ + RestDuration( + beginDate: DateTime.parse("2020-09-20"), + createdDate: DateTime.parse("2020-09-20"), + endDate: null), + ], + ); + expect(model.isActive, true); + }); + test( + "it is active pattern. for avoid out of active duration when contains ended rest duration", + () { + final mockTodayRepository = MockTodayService(); + todayRepository = mockTodayRepository; + when(mockTodayRepository.now()) + .thenReturn(DateTime(2020, 9, 29, 23, 59, 59)); + when(mockTodayRepository.today()) + .thenReturn(DateTime.parse("2020-09-29")); + + final sheetType = PillSheetType.pillsheet_21; + final model = PillSheet( beginingDate: DateTime.parse("2020-09-01"), typeInfo: PillSheetTypeInfo( dosingPeriod: sheetType.dosingPeriod, @@ -125,19 +292,25 @@ void main() { totalCount: sheetType.totalCount, pillSheetTypeReferencePath: sheetType.rawPath, ), + restDurations: [ + RestDuration( + beginDate: DateTime.parse("2020-09-20"), + createdDate: DateTime.parse("2020-09-20"), + endDate: DateTime.parse("2020-09-22")), + ], ); expect(model.isActive, true); }); test( "it is deactive pattern. Boundary testing. now: 2020-09-29 23:59:59, begin: 2020-09-01", () { - var mockTodayRepository = MockTodayService(); + final mockTodayRepository = MockTodayService(); todayRepository = mockTodayRepository; when(mockTodayRepository.now()) .thenReturn(DateTime(2020, 9, 29, 23, 59, 59)); - var sheetType = PillSheetType.pillsheet_21; - var model = PillSheet( + final sheetType = PillSheetType.pillsheet_21; + final model = PillSheet( beginingDate: DateTime.parse("2020-09-01"), typeInfo: PillSheetTypeInfo( dosingPeriod: sheetType.dosingPeriod, @@ -149,12 +322,32 @@ void main() { expect(model.isActive, false); }); test("it is deactive pattern. now: 2020-06-29 begin: 2020-09-01", () { - var mockTodayRepository = MockTodayService(); + final mockTodayRepository = MockTodayService(); todayRepository = mockTodayRepository; when(mockTodayRepository.now()).thenReturn(DateTime.parse("2020-06-29")); - var sheetType = PillSheetType.pillsheet_21; - var model = PillSheet( + final sheetType = PillSheetType.pillsheet_21; + final model = PillSheet( + beginingDate: DateTime.parse("2020-09-01"), + typeInfo: PillSheetTypeInfo( + dosingPeriod: sheetType.dosingPeriod, + name: sheetType.fullName, + totalCount: sheetType.totalCount, + pillSheetTypeReferencePath: sheetType.rawPath, + ), + ); + expect(model.isActive, false); + }); + test("it is deactive pattern. for contains ended rest duration", () { + final mockTodayRepository = MockTodayService(); + todayRepository = mockTodayRepository; + when(mockTodayRepository.now()) + .thenReturn(DateTime(2020, 9, 30, 23, 59, 59)); + when(mockTodayRepository.today()) + .thenReturn(DateTime.parse("2020-09-30")); + + final sheetType = PillSheetType.pillsheet_21; + final model = PillSheet( beginingDate: DateTime.parse("2020-09-01"), typeInfo: PillSheetTypeInfo( dosingPeriod: sheetType.dosingPeriod, @@ -162,6 +355,13 @@ void main() { totalCount: sheetType.totalCount, pillSheetTypeReferencePath: sheetType.rawPath, ), + restDurations: [ + RestDuration( + beginDate: DateTime.parse("2020-09-20"), + createdDate: DateTime.parse("2020-09-20"), + endDate: DateTime.parse("2020-09-21"), + ), + ], ); expect(model.isActive, false); }); @@ -169,12 +369,12 @@ void main() { group("#isReached", () { test("it is not out of range pattern. today: 2020-09-19, begin: 2020-09-14", () { - var mockTodayRepository = MockTodayService(); + final mockTodayRepository = MockTodayService(); todayRepository = mockTodayRepository; when(mockTodayRepository.now()).thenReturn(DateTime.parse("2020-09-19")); - var sheetType = PillSheetType.pillsheet_21; - var model = PillSheet( + final sheetType = PillSheetType.pillsheet_21; + final model = PillSheet( beginingDate: DateTime.parse("2020-09-14"), typeInfo: PillSheetTypeInfo( dosingPeriod: sheetType.dosingPeriod, @@ -188,12 +388,12 @@ void main() { test( "it is not out of range pattern. Boundary testing. now: 2020-09-28, begin: 2020-09-01", () { - var mockTodayRepository = MockTodayService(); + final mockTodayRepository = MockTodayService(); todayRepository = mockTodayRepository; when(mockTodayRepository.now()).thenReturn(DateTime.parse("2020-09-28")); - var sheetType = PillSheetType.pillsheet_21; - var model = PillSheet( + final sheetType = PillSheetType.pillsheet_21; + final model = PillSheet( beginingDate: DateTime.parse("2020-09-01"), typeInfo: PillSheetTypeInfo( dosingPeriod: sheetType.dosingPeriod, @@ -207,12 +407,12 @@ void main() { test( "it is out of range pattern. Boundary testing. now: 2020-09-29, begin: 2020-09-01", () { - var mockTodayRepository = MockTodayService(); + final mockTodayRepository = MockTodayService(); todayRepository = mockTodayRepository; when(mockTodayRepository.now()).thenReturn(DateTime.parse("2020-09-29")); - var sheetType = PillSheetType.pillsheet_21; - var model = PillSheet( + final sheetType = PillSheetType.pillsheet_21; + final model = PillSheet( beginingDate: DateTime.parse("2020-09-01"), typeInfo: PillSheetTypeInfo( dosingPeriod: sheetType.dosingPeriod, @@ -224,12 +424,12 @@ void main() { expect(model.isReached, true); }); test("it is out of range pattern. now: 2020-06-29, begin: 2020-09-01", () { - var mockTodayRepository = MockTodayService(); + final mockTodayRepository = MockTodayService(); todayRepository = mockTodayRepository; when(mockTodayRepository.now()).thenReturn(DateTime.parse("2020-06-29")); - var sheetType = PillSheetType.pillsheet_21; - var model = PillSheet( + final sheetType = PillSheetType.pillsheet_21; + final model = PillSheet( beginingDate: DateTime.parse("2020-09-01"), typeInfo: PillSheetTypeInfo( dosingPeriod: sheetType.dosingPeriod, @@ -241,10 +441,216 @@ void main() { expect(model.isReached, false); }); }); + group("#lastTakenDate", () { + test("it is not taken yet", () { + final mockTodayRepository = MockTodayService(); + todayRepository = mockTodayRepository; + when(mockTodayRepository.now()).thenReturn(DateTime.parse("2020-09-19")); + + final sheetType = PillSheetType.pillsheet_21; + final model = PillSheet( + beginingDate: DateTime.parse("2020-09-14"), + typeInfo: PillSheetTypeInfo( + dosingPeriod: sheetType.dosingPeriod, + name: sheetType.fullName, + totalCount: sheetType.totalCount, + pillSheetTypeReferencePath: sheetType.rawPath, + ), + ); + expect(model.lastTakenPillNumber, 0); + }); + test("it is taken", () { + final mockTodayRepository = MockTodayService(); + todayRepository = mockTodayRepository; + when(mockTodayRepository.now()).thenReturn(DateTime.parse("2020-09-19")); + + final sheetType = PillSheetType.pillsheet_21; + final model = PillSheet( + beginingDate: DateTime.parse("2020-09-14"), + lastTakenDate: DateTime.parse("2020-09-17"), + typeInfo: PillSheetTypeInfo( + dosingPeriod: sheetType.dosingPeriod, + name: sheetType.fullName, + totalCount: sheetType.totalCount, + pillSheetTypeReferencePath: sheetType.rawPath, + ), + ); + expect(model.lastTakenPillNumber, 4); + }); + test("it is boundary test", () { + final mockTodayRepository = MockTodayService(); + todayRepository = mockTodayRepository; + when(mockTodayRepository.now()).thenReturn(DateTime.parse("2020-09-28")); + + final sheetType = PillSheetType.pillsheet_21; + final model = PillSheet( + beginingDate: DateTime.parse("2020-09-01"), + lastTakenDate: DateTime.parse("2020-09-28"), + typeInfo: PillSheetTypeInfo( + dosingPeriod: sheetType.dosingPeriod, + name: sheetType.fullName, + totalCount: sheetType.totalCount, + pillSheetTypeReferencePath: sheetType.rawPath, + ), + ); + expect(model.lastTakenPillNumber, 28); + }); + group("pillsheet has rest durations", () { + test("rest duration is not ended", () { + final mockTodayRepository = MockTodayService(); + todayRepository = mockTodayRepository; + when(mockTodayRepository.now()) + .thenReturn(DateTime.parse("2020-09-28")); + when(mockTodayRepository.today()) + .thenReturn(DateTime.parse("2020-09-28")); + + final sheetType = PillSheetType.pillsheet_21; + final model = PillSheet( + beginingDate: DateTime.parse("2020-09-01"), + lastTakenDate: DateTime.parse("2020-09-22"), + restDurations: [ + RestDuration( + beginDate: DateTime.parse("2020-09-23"), + createdDate: DateTime.parse("2020-09-23"), + ), + ], + typeInfo: PillSheetTypeInfo( + dosingPeriod: sheetType.dosingPeriod, + name: sheetType.fullName, + totalCount: sheetType.totalCount, + pillSheetTypeReferencePath: sheetType.rawPath, + ), + ); + expect(model.lastTakenPillNumber, 22); + }); + test("rest duration is ended", () { + final mockTodayRepository = MockTodayService(); + todayRepository = mockTodayRepository; + when(mockTodayRepository.now()) + .thenReturn(DateTime.parse("2020-09-28")); + + final sheetType = PillSheetType.pillsheet_21; + final model = PillSheet( + beginingDate: DateTime.parse("2020-09-01"), + lastTakenDate: DateTime.parse("2020-09-27"), + restDurations: [ + RestDuration( + beginDate: DateTime.parse("2020-09-23"), + createdDate: DateTime.parse("2020-09-23"), + endDate: DateTime.parse("2020-09-25"), + ), + ], + typeInfo: PillSheetTypeInfo( + dosingPeriod: sheetType.dosingPeriod, + name: sheetType.fullName, + totalCount: sheetType.totalCount, + pillSheetTypeReferencePath: sheetType.rawPath, + ), + ); + expect(model.lastTakenPillNumber, 25); + }); + test("rest duration is ended and not yet taken pill", () { + final mockTodayRepository = MockTodayService(); + todayRepository = mockTodayRepository; + when(mockTodayRepository.now()) + .thenReturn(DateTime.parse("2020-09-28")); + + final sheetType = PillSheetType.pillsheet_21; + final model = PillSheet( + beginingDate: DateTime.parse("2020-09-01"), + lastTakenDate: null, + restDurations: [ + RestDuration( + beginDate: DateTime.parse("2020-09-23"), + createdDate: DateTime.parse("2020-09-23"), + endDate: DateTime.parse("2020-09-25"), + ), + ], + typeInfo: PillSheetTypeInfo( + dosingPeriod: sheetType.dosingPeriod, + name: sheetType.fullName, + totalCount: sheetType.totalCount, + pillSheetTypeReferencePath: sheetType.rawPath, + ), + ); + expect(model.lastTakenPillNumber, 0); + }); + + group("pillsheet has plural rest durations", () { + test("last rest duration is not ended", () { + final mockTodayRepository = MockTodayService(); + todayRepository = mockTodayRepository; + when(mockTodayRepository.now()) + .thenReturn(DateTime.parse("2020-09-28")); + when(mockTodayRepository.today()) + .thenReturn(DateTime.parse("2020-09-28")); + + final sheetType = PillSheetType.pillsheet_21; + final model = PillSheet( + beginingDate: DateTime.parse("2020-09-01"), + lastTakenDate: DateTime.parse("2020-09-22"), + restDurations: [ + RestDuration( + beginDate: DateTime.parse("2020-09-12"), + createdDate: DateTime.parse("2020-09-12"), + endDate: DateTime.parse("2020-09-15"), + ), + RestDuration( + beginDate: DateTime.parse("2020-09-26"), + createdDate: DateTime.parse("2020-09-26"), + ), + ], + typeInfo: PillSheetTypeInfo( + dosingPeriod: sheetType.dosingPeriod, + name: sheetType.fullName, + totalCount: sheetType.totalCount, + pillSheetTypeReferencePath: sheetType.rawPath, + ), + ); + expect(model.lastTakenPillNumber, 19); + }); + test("last rest duration is ended", () { + final mockTodayRepository = MockTodayService(); + todayRepository = mockTodayRepository; + when(mockTodayRepository.now()) + .thenReturn(DateTime.parse("2020-09-28")); + + final sheetType = PillSheetType.pillsheet_21; + final model = PillSheet( + beginingDate: DateTime.parse("2020-09-01"), + lastTakenDate: DateTime.parse("2020-09-22"), + restDurations: [ + RestDuration( + beginDate: DateTime.parse("2020-09-12"), + createdDate: DateTime.parse("2020-09-12"), + endDate: DateTime.parse("2020-09-15"), + ), + RestDuration( + beginDate: DateTime.parse("2020-09-26"), + createdDate: DateTime.parse("2020-09-26"), + endDate: DateTime.parse("2020-09-27"), + ), + ], + typeInfo: PillSheetTypeInfo( + dosingPeriod: sheetType.dosingPeriod, + name: sheetType.fullName, + totalCount: sheetType.totalCount, + pillSheetTypeReferencePath: sheetType.rawPath, + ), + ); + expect(model.lastTakenPillNumber, 19); + }); + }); + }); + }); group("#estimatedLastTakenDate", () { test("spec", () { - var sheetType = PillSheetType.pillsheet_21; - var pillSheet = PillSheet( + final mockTodayRepository = MockTodayService(); + todayRepository = mockTodayRepository; + when(mockTodayRepository.now()).thenReturn(DateTime.parse("2022-05-10")); + + final sheetType = PillSheetType.pillsheet_21; + final pillSheet = PillSheet( beginingDate: DateTime.parse("2022-05-01"), typeInfo: PillSheetTypeInfo( dosingPeriod: sheetType.dosingPeriod, @@ -256,5 +662,170 @@ void main() { expect(pillSheet.estimatedLastTakenDate, DateTime.parse("2022-05-29").subtract(Duration(seconds: 1))); }); + + group("pillsheet has rest durations", () { + test("rest duration is not ended", () { + final mockTodayRepository = MockTodayService(); + todayRepository = mockTodayRepository; + when(mockTodayRepository.now()) + .thenReturn(DateTime.parse("2022-05-10")); + when(mockTodayRepository.today()) + .thenReturn(DateTime.parse("2022-05-10")); + + final sheetType = PillSheetType.pillsheet_21; + final pillSheet = PillSheet( + beginingDate: DateTime.parse("2022-05-01"), + restDurations: [ + RestDuration( + beginDate: DateTime.parse("2022-05-03"), + createdDate: DateTime.parse("2022-05-03"), + ), + ], + typeInfo: PillSheetTypeInfo( + dosingPeriod: sheetType.dosingPeriod, + name: sheetType.fullName, + totalCount: sheetType.totalCount, + pillSheetTypeReferencePath: sheetType.rawPath, + ), + ); + expect(pillSheet.estimatedLastTakenDate, + DateTime.parse("2022-06-05").subtract(Duration(seconds: 1))); + }); + test("rest duration is ended", () { + final mockTodayRepository = MockTodayService(); + todayRepository = mockTodayRepository; + when(mockTodayRepository.now()) + .thenReturn(DateTime.parse("2022-05-10")); + + final sheetType = PillSheetType.pillsheet_21; + final pillSheet = PillSheet( + beginingDate: DateTime.parse("2022-05-01"), + restDurations: [ + RestDuration( + beginDate: DateTime.parse("2022-05-03"), + createdDate: DateTime.parse("2022-05-03"), + endDate: DateTime.parse("2022-05-05"), + ), + ], + typeInfo: PillSheetTypeInfo( + dosingPeriod: sheetType.dosingPeriod, + name: sheetType.fullName, + totalCount: sheetType.totalCount, + pillSheetTypeReferencePath: sheetType.rawPath, + ), + ); + expect(pillSheet.estimatedLastTakenDate, + DateTime.parse("2022-05-31").subtract(Duration(seconds: 1))); + }); + + group("pillsheet has plural rest duration", () { + test("last rest duration is not ended", () { + final mockTodayRepository = MockTodayService(); + todayRepository = mockTodayRepository; + when(mockTodayRepository.now()) + .thenReturn(DateTime.parse("2022-05-10")); + when(mockTodayRepository.today()) + .thenReturn(DateTime.parse("2022-05-10")); + + final sheetType = PillSheetType.pillsheet_21; + final pillSheet = PillSheet( + beginingDate: DateTime.parse("2022-05-01"), + restDurations: [ + RestDuration( + beginDate: DateTime.parse("2022-05-03"), + createdDate: DateTime.parse("2022-05-03"), + endDate: DateTime.parse("2022-05-05"), + ), + RestDuration( + beginDate: DateTime.parse("2022-05-07"), + createdDate: DateTime.parse("2022-05-07"), + ), + ], + typeInfo: PillSheetTypeInfo( + dosingPeriod: sheetType.dosingPeriod, + name: sheetType.fullName, + totalCount: sheetType.totalCount, + pillSheetTypeReferencePath: sheetType.rawPath, + ), + ); + expect(pillSheet.estimatedLastTakenDate, + DateTime.parse("2022-06-03").subtract(Duration(seconds: 1))); + }); + test("last rest duration is ended", () { + final mockTodayRepository = MockTodayService(); + todayRepository = mockTodayRepository; + when(mockTodayRepository.now()) + .thenReturn(DateTime.parse("2022-05-10")); + when(mockTodayRepository.today()) + .thenReturn(DateTime.parse("2022-05-10")); + + final sheetType = PillSheetType.pillsheet_21; + final pillSheet = PillSheet( + beginingDate: DateTime.parse("2022-05-01"), + restDurations: [ + RestDuration( + beginDate: DateTime.parse("2022-05-03"), + createdDate: DateTime.parse("2022-05-03"), + endDate: DateTime.parse("2022-05-05"), + ), + RestDuration( + beginDate: DateTime.parse("2022-05-07"), + createdDate: DateTime.parse("2022-05-07"), + endDate: DateTime.parse("2022-05-08"), + ), + ], + typeInfo: PillSheetTypeInfo( + dosingPeriod: sheetType.dosingPeriod, + name: sheetType.fullName, + totalCount: sheetType.totalCount, + pillSheetTypeReferencePath: sheetType.rawPath, + ), + ); + expect(pillSheet.estimatedLastTakenDate, + DateTime.parse("2022-06-01").subtract(Duration(seconds: 1))); + }); + }); + }); + group("#summarizedRestDuration", () { + test("restDurations isEmpty", () { + final mockTodayRepository = MockTodayService(); + todayRepository = mockTodayRepository; + when(mockTodayRepository.now()) + .thenReturn(DateTime.parse("2022-05-10")); + when(mockTodayRepository.today()) + .thenReturn(DateTime.parse("2022-05-10")); + + expect(summarizedRestDuration([]), 0); + }); + test("last restDuration is not ended", () { + final mockTodayRepository = MockTodayService(); + todayRepository = mockTodayRepository; + when(mockTodayRepository.today()) + .thenReturn(DateTime.parse("2022-05-10")); + + final restDurations = [ + RestDuration( + beginDate: DateTime.parse("2022-05-07"), + createdDate: DateTime.parse("2022-05-07"), + ), + ]; + expect(summarizedRestDuration(restDurations), 3); + }); + test("last restDuration is ended", () { + final mockTodayRepository = MockTodayService(); + todayRepository = mockTodayRepository; + when(mockTodayRepository.now()) + .thenReturn(DateTime.parse("2022-05-10")); + + final restDurations = [ + RestDuration( + beginDate: DateTime.parse("2022-05-07"), + createdDate: DateTime.parse("2022-05-07"), + endDate: DateTime.parse("2022-05-08"), + ), + ]; + expect(summarizedRestDuration(restDurations), 1); + }); + }); }); } diff --git a/test/helper/mock.mocks.dart b/test/helper/mock.mocks.dart index 4a63c7ab52..8f3fe0805b 100644 --- a/test/helper/mock.mocks.dart +++ b/test/helper/mock.mocks.dart @@ -499,6 +499,30 @@ class MockRecordPageStore extends _i1.Mock implements _i25.RecordPageStore { dynamic removePillSheetType(int? index, _i3.Setting? setting) => super .noSuchMethod(Invocation.method(#removePillSheetType, [index, setting])); @override + _i17.Future beginResting( + {_i11.PillSheetGroup? pillSheetGroup, + _i2.PillSheet? activedPillSheet}) => + (super.noSuchMethod( + Invocation.method(#beginResting, [], { + #pillSheetGroup: pillSheetGroup, + #activedPillSheet: activedPillSheet + }), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i17.Future); + @override + _i17.Future endResting( + {_i11.PillSheetGroup? pillSheetGroup, + _i2.PillSheet? activedPillSheet, + _i2.RestDuration? restDuration}) => + (super.noSuchMethod( + Invocation.method(#endResting, [], { + #pillSheetGroup: pillSheetGroup, + #activedPillSheet: activedPillSheet, + #restDuration: restDuration + }), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i17.Future); + @override _i26.RemoveListener addListener(_i26.Listener<_i7.RecordPageState>? listener, {bool? fireImmediately = true}) => (super.noSuchMethod( diff --git a/test/util/day_test.dart b/test/util/day_test.dart new file mode 100644 index 0000000000..6355d2ec77 --- /dev/null +++ b/test/util/day_test.dart @@ -0,0 +1,25 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:pilll/util/datetime/day.dart'; + +void main() { + group("#daysBetween", () { + test("difference in 1 hour", () { + DateTime date1 = DateTime.parse("2020-01-09 23:00:00.299871"); + DateTime date2 = DateTime.parse("2020-01-10 00:00:00.299871"); + + expect(daysBetween(date1, date2), 1); + }); + test("difference in 1 minute", () { + DateTime date1 = DateTime.parse("2020-01-09 23:59:59.299871"); + DateTime date2 = DateTime.parse("2020-01-10 00:00:00.299871"); + + expect(daysBetween(date1, date2), 1); + }); + test("it is same day", () { + DateTime date1 = DateTime.parse("2020-01-10 00:00:00.299871"); + DateTime date2 = DateTime.parse("2020-01-10 23:59:59.299871"); + + expect(daysBetween(date1, date2), 0); + }); + }); +}