Skip to content

Commit 58b1e39

Browse files
authored
schedules: show dates and month headers (#135)
1 parent cf21738 commit 58b1e39

File tree

15 files changed

+152
-46
lines changed

15 files changed

+152
-46
lines changed

integration_test/app_test.dart

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -750,6 +750,40 @@ void main() async {
750750
.providerContainer;
751751
await tester.tap(find.byType(PlanCard).first);
752752
await tester.pumpAndSettle();
753+
await tester.scrollUntilVisible(
754+
find.byKey(const Key('day-74')),
755+
-500.0,
756+
);
757+
await tester.pumpAndSettle();
758+
759+
// Day indices are shown as there is no target date yet in the model.
760+
expect(find.byKey(const Key('date')), findsNothing);
761+
expect(find.byKey(const Key('day-index')), findsWidgets);
762+
expect(
763+
(tester.firstWidget(find.byKey(const Key('day-index'))) as Text).data,
764+
'75');
765+
766+
await tester.tap(find
767+
.descendant(
768+
of: find.byKey(const Key('day-74')),
769+
matching: find.byType(IconButton))
770+
.first);
771+
await tester.pumpAndSettle();
772+
773+
final dayOfMonth = DateTime.now().day;
774+
expect(find.byKey(const Key('date')), findsWidgets);
775+
expect(find.byKey(const Key('day-index')), findsNothing);
776+
expect((tester.firstWidget(find.byKey(const Key('date'))) as Text).data,
777+
dayOfMonth.toString());
778+
779+
await tester.scrollUntilVisible(
780+
find.byKey(Key('day-${(74 - dayOfMonth).toString()}')),
781+
-500.0,
782+
);
783+
await tester.pumpAndSettle();
784+
785+
expect(find.byKey(const Key('month')), findsOneWidget);
786+
753787
await tester.tap(find.byIcon(Icons.edit));
754788
await tester.pumpAndSettle();
755789
await tester.tap(find.byKey(const Key('with-target-date')));
@@ -763,6 +797,17 @@ void main() async {
763797

764798
plan = providerContainer.read(plansProvider).plans.first;
765799
expect(plan.withTargetDate, false);
800+
expect(find.byKey(const Key('month')), findsNothing);
801+
expect(find.byKey(const Key('date')), findsNothing);
802+
expect(find.byKey(const Key('day-index')), findsWidgets);
803+
expect(
804+
(tester.firstWidget(find
805+
.descendant(
806+
of: find.byKey(Key('day-${(74 - dayOfMonth).toString()}')),
807+
matching: find.byKey(const Key('day-index')))
808+
.last) as Text)
809+
.data,
810+
(75 - dayOfMonth).toString());
766811

767812
await tester.tap(find.byIcon(Icons.edit));
768813
await tester.pumpAndSettle();

lib/src/localization/app_cz.arb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"plansPageNoPlanYet": "Zatím žádný plán čtení Bible. Přidej jeden.",
77
"plansPageAddPlanTooltip": "Přidat",
88
"plansPageCardRemainingDays": "{remainingDays}d",
9+
"schedulePageCardWeekday": "{date}",
910
"schedulePageJumpToBookmarkTooltip": "Přejít na záložku",
1011
"schedulePageEventCommonEraTerm": "{isCE, select, true{n. l.} other{př. n. l.}}",
1112
"schedulePageToggleReadDialogTitle": "Přepínání čtení",

lib/src/localization/app_de.arb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"plansPageNoPlanYet": "Noch kein Bibel-Leseplan. Füge einen hinzu.",
77
"plansPageAddPlanTooltip": "Hinzufügen",
88
"plansPageCardRemainingDays": "{remainingDays}T",
9+
"schedulePageCardWeekday": "{date}",
910
"schedulePageJumpToBookmarkTooltip": "Springe zum Lesezeichen",
1011
"schedulePageEventCommonEraTerm": "{isCE, select, true{u. Z.} other{v. u. Z.}}",
1112
"schedulePageToggleReadDialogTitle": "Lesestatus ändern",

lib/src/localization/app_en.arb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,16 @@
2626
}
2727
}
2828
},
29+
"schedulePageCardWeekday": "{date}",
30+
"@schedulePageCardWeekday": {
31+
"description": "Displaying the weekday on the day card on the schedule page.",
32+
"placeholders": {
33+
"date": {
34+
"type": "DateTime",
35+
"format": "E"
36+
}
37+
}
38+
},
2939
"schedulePageJumpToBookmarkTooltip": "Jump to bookmark",
3040
"@schedulePageJumpToBookmarkTooltip": {
3141
"description": "The tooltip on the jump to bookmark button on the schedule page"

lib/src/localization/app_es.arb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"plansPageNoPlanYet": "Aún no hay un plan de lectura de la Biblia. Añade uno.",
77
"plansPageAddPlanTooltip": "Añadir",
88
"plansPageCardRemainingDays": "{remainingDays}d",
9+
"schedulePageCardWeekday": "{date}",
910
"schedulePageJumpToBookmarkTooltip": "Saltar al marcador",
1011
"schedulePageEventCommonEraTerm": "{isCE, select, true{d.C.} other{a.C.}}",
1112
"schedulePageToggleReadDialogTitle": "Alternar lectura",

lib/src/localization/app_fr.arb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"plansPageNoPlanYet": "Pas encore de plan de lecture de la Bible. Ajoute-en un.",
77
"plansPageAddPlanTooltip": "Ajouter",
88
"plansPageCardRemainingDays": "{remainingDays}j",
9+
"schedulePageCardWeekday": "{date}",
910
"schedulePageJumpToBookmarkTooltip": "Aller au marque-page",
1011
"schedulePageEventCommonEraTerm": "{isCE, select, true{de notre ère} other{avant notre ère}}",
1112
"schedulePageToggleReadDialogTitle": "Basculer la lecture",

lib/src/localization/app_hu.arb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"plansPageNoPlanYet": "Még nincs bibliaolvasási terv. Adj hozzá egyet.",
77
"plansPageAddPlanTooltip": "Hozzáadás",
88
"plansPageCardRemainingDays": "{remainingDays}n",
9+
"schedulePageCardWeekday": "{date}",
910
"schedulePageJumpToBookmarkTooltip": "Ugrás a könyvjelzőhöz",
1011
"schedulePageEventCommonEraTerm": "{isCE, select, true{i.sz.} other{i.e.}}",
1112
"schedulePageToggleReadDialogTitle": "Olvasás váltása",

lib/src/localization/app_it.arb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"plansPageNoPlanYet": "Ancora nessun piano di lettura della Bibbia. Aggiungine uno.",
77
"plansPageAddPlanTooltip": "Aggiungi",
88
"plansPageCardRemainingDays": "{remainingDays}g",
9+
"schedulePageCardWeekday": "{date}",
910
"schedulePageJumpToBookmarkTooltip": "Vai al segnalibro",
1011
"schedulePageEventCommonEraTerm": "{isCE, select, true{d.C.} other{a.C.}}",
1112
"schedulePageToggleReadDialogTitle": "Alterna lettura",

lib/src/localization/app_pl.arb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"plansPageNoPlanYet": "Brak planu czytania Biblii. Dodaj jeden.",
77
"plansPageAddPlanTooltip": "Dodaj",
88
"plansPageCardRemainingDays": "{remainingDays}d",
9+
"schedulePageCardWeekday": "{date}",
910
"schedulePageJumpToBookmarkTooltip": "Przejdź do zakładki",
1011
"schedulePageEventCommonEraTerm": "{isCE, select, true{n.e.} other{p.n.e.}}",
1112
"schedulePageToggleReadDialogTitle": "Przełączanie czytania",

lib/src/localization/app_pt.arb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"plansPageNoPlanYet": "Ainda não há um plano de leitura da Bíblia. Adicione um.",
77
"plansPageAddPlanTooltip": "Adicionar",
88
"plansPageCardRemainingDays": "{remainingDays}d",
9+
"schedulePageCardWeekday": "{date}",
910
"schedulePageJumpToBookmarkTooltip": "Ir para o marcador",
1011
"schedulePageEventCommonEraTerm": "{isCE, select, true{d.C.} other{a.C.}}",
1112
"schedulePageToggleReadDialogTitle": "Alternar leitura",

lib/src/localization/app_ro.arb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"plansPageNoPlanYet": "Încă nu există un plan de citire a Bibliei. Adaugă unul.",
77
"plansPageAddPlanTooltip": "Adaugă",
88
"plansPageCardRemainingDays": "{remainingDays}z",
9+
"schedulePageCardWeekday": "{date}",
910
"schedulePageJumpToBookmarkTooltip": "Sari la marcaj",
1011
"schedulePageEventCommonEraTerm": "{isCE, select, true{e.n.} other{î.e.n.}}",
1112
"schedulePageToggleReadDialogTitle": "Comutare citire",

lib/src/localization/app_ru.arb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"plansPageNoPlanYet": "План чтения Библии пока не добавлен. Добавь один.",
77
"plansPageAddPlanTooltip": "Добавить",
88
"plansPageCardRemainingDays": "{remainingDays}д",
9+
"schedulePageCardWeekday": "{date}",
910
"schedulePageJumpToBookmarkTooltip": "Перейти к закладке",
1011
"schedulePageEventCommonEraTerm": "{isCE, select, true{н.э.} other{до н.э.}}",
1112
"schedulePageToggleReadDialogTitle": "Переключение чтения",

lib/src/schedules/presentations/day_card.dart

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
import 'package:flutter/material.dart';
2+
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
23
import 'package:flutter_riverpod/flutter_riverpod.dart';
34
import 'package:nwt_reading/src/schedules/entities/schedule.dart';
45
import 'package:nwt_reading/src/schedules/presentations/section_widget.dart';
56

67
class DayCard extends ConsumerWidget {
78
const DayCard(
89
{super.key,
10+
required this.date,
911
required this.planId,
1012
required this.day,
1113
required this.dayIndex});
14+
final DateTime? date;
1215
final String planId;
1316
final Day day;
1417
final int dayIndex;
@@ -34,9 +37,26 @@ class DayCard extends ConsumerWidget {
3437
)),
3538
Container(
3639
padding: const EdgeInsets.fromLTRB(0, 0, 4, 0),
37-
width: 25,
38-
child: Text((dayIndex + 1).toString(),
39-
style: Theme.of(context).textTheme.bodySmall)),
40+
width: 40,
41+
child: date == null
42+
? Text((dayIndex + 1).toString(),
43+
key: const Key('day-index'),
44+
style: Theme.of(context).textTheme.bodySmall)
45+
: Column(
46+
crossAxisAlignment: CrossAxisAlignment.end,
47+
children: [
48+
Text(
49+
date!.day.toString(),
50+
key: const Key('date'),
51+
style: Theme.of(context).textTheme.bodySmall,
52+
),
53+
Text(
54+
AppLocalizations.of(context)
55+
.schedulePageCardWeekday(date!),
56+
style: Theme.of(context).textTheme.bodySmall,
57+
)
58+
],
59+
)),
4060
],
4161
),
4262
),

lib/src/schedules/presentations/schedule_page.dart

Lines changed: 60 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,7 @@ class _SchedulePageState extends ConsumerState<SchedulePage> {
3535
final planId = ModalRoute.of(context)!.settings.arguments as String;
3636
final plan = ref.watch(planProviderFamily(planId));
3737
final planNotifier = ref.read(planProviderFamily(planId).notifier);
38-
final schedule =
39-
ref.watch(scheduleProviderFamily(plan.scheduleKey)).valueOrNull;
38+
final asyncSchedule = ref.watch(scheduleProviderFamily(plan.scheduleKey));
4039
final progress = planNotifier.getProgress();
4140
const Key centerKey = ValueKey<String>('today');
4241
final controller = ScrollController();
@@ -48,20 +47,24 @@ class _SchedulePageState extends ConsumerState<SchedulePage> {
4847
resetTopDayIndex(plan.bookmark);
4948
}
5049

51-
Widget? scheduleListBuilder(int index) {
52-
final day = schedule?.days[index];
50+
Widget? scheduleListBuilder(Schedule schedule, int index) {
51+
final day = schedule.days[index];
5352
final isCurrentDay = plan.bookmark.dayIndex == index;
5453
final isTargetDay = todayTargetIndex == index;
5554
final dividerColor = isCurrentDay ? Colors.blue : badgeColor;
56-
final dayCard = day == null
57-
? null
58-
: DayCard(
59-
key: Key('day-$index'),
60-
planId: planId,
61-
day: day,
62-
dayIndex: index);
63-
64-
return dayCard != null && (isCurrentDay || isTargetDay)
55+
final remainingDays = planNotifier
56+
.getRemainingDays(Bookmark(dayIndex: index, sectionIndex: 0));
57+
final date = plan.withTargetDate && remainingDays != null
58+
? plan.targetDate?.subtract(Duration(days: remainingDays))
59+
: null;
60+
final isBeginningOfMonth = date?.day == 1;
61+
final dayCard = DayCard(
62+
date: date,
63+
key: Key('day-$index'),
64+
planId: planId,
65+
day: day,
66+
dayIndex: index);
67+
final dayCardWithDivider = (isCurrentDay || isTargetDay)
6568
? Column(
6669
children: [
6770
Container(
@@ -85,6 +88,20 @@ class _SchedulePageState extends ConsumerState<SchedulePage> {
8588
],
8689
)
8790
: dayCard;
91+
92+
return date != null && plan.withTargetDate && isBeginningOfMonth
93+
? Column(
94+
// crossAxisAlignment: CrossAxisAlignment.start,
95+
children: [
96+
Text(
97+
MaterialLocalizations.of(context).formatMonthYear(date),
98+
key: const Key('month'),
99+
style: Theme.of(context).textTheme.headlineSmall,
100+
),
101+
dayCardWithDivider,
102+
],
103+
)
104+
: dayCardWithDivider;
88105
}
89106

90107
return Scaffold(
@@ -107,35 +124,39 @@ class _SchedulePageState extends ConsumerState<SchedulePage> {
107124
),
108125
],
109126
),
110-
body: schedule == null
111-
? null
112-
: Column(
113-
children: [
114-
LinearProgressIndicator(value: progress),
115-
Flexible(
116-
child: CustomScrollView(
117-
controller: controller,
118-
center: centerKey,
119-
slivers: <Widget>[
120-
SliverList(
121-
delegate: SliverChildBuilderDelegate(
122-
(BuildContext context, int index) =>
123-
scheduleListBuilder(topDayIndex - 1 - index),
124-
childCount: topDayIndex),
125-
),
126-
SliverList(
127-
key: centerKey,
128-
delegate: SliverChildBuilderDelegate(
127+
body: switch (asyncSchedule) {
128+
AsyncValue(:final valueOrNull?) => Column(
129+
children: [
130+
LinearProgressIndicator(value: progress),
131+
Flexible(
132+
child: CustomScrollView(
133+
controller: controller,
134+
center: centerKey,
135+
slivers: <Widget>[
136+
SliverList(
137+
delegate: SliverChildBuilderDelegate(
129138
(BuildContext context, int index) =>
130-
scheduleListBuilder(topDayIndex + index),
131-
childCount: schedule.days.length - topDayIndex,
132-
),
139+
scheduleListBuilder(
140+
valueOrNull, topDayIndex - 1 - index),
141+
childCount: topDayIndex),
142+
),
143+
SliverList(
144+
key: centerKey,
145+
delegate: SliverChildBuilderDelegate(
146+
(BuildContext context, int index) =>
147+
scheduleListBuilder(
148+
valueOrNull, topDayIndex + index),
149+
childCount: valueOrNull.days.length - topDayIndex,
133150
),
134-
],
135-
),
151+
),
152+
],
136153
),
137-
],
138-
),
154+
),
155+
],
156+
),
157+
AsyncValue(:final error?) => Text('Error: $error'),
158+
_ => const Center(child: CircularProgressIndicator()),
159+
},
139160
floatingActionButton: FloatingActionButton(
140161
tooltip:
141162
AppLocalizations.of(context).schedulePageJumpToBookmarkTooltip,

test/test_plans.dart

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ final Plans testPlans = Plans([
2727
version: '1.0'),
2828
language: 'de',
2929
bookmark: Bookmark(dayIndex: 0, sectionIndex: -1),
30-
withTargetDate: true,
31-
showEvents: true,
32-
showLocations: true),
30+
withTargetDate: false,
31+
showEvents: false,
32+
showLocations: false),
3333
Plan(
3434
id: '2dab49f3-aecf-4aba-9e91-d75c297d4b7e',
3535
name: 'Sequential',
@@ -59,7 +59,7 @@ final Plans testPlans = Plans([
5959

6060
const List<String> testPlansSerialized = [
6161
'{"id":"5aa4de9e-036b-42cd-8bcb-a92cae46db27","name":"Chronological y1","scheduleKey":{"type":0,"duration":2,"version":"1.0"},"language":"en","bookmark":{"dayIndex":75,"sectionIndex":0},"withTargetDate":true,"showEvents":true,"showLocations":true}',
62-
'{"id":"0da6b8a7-ccd4-4270-8058-9e30a3f55ceb","name":"Written","scheduleKey":{"type":2,"duration":2,"version":"1.0"},"language":"de","bookmark":{"dayIndex":0,"sectionIndex":-1},"withTargetDate":true,"showEvents":true,"showLocations":true}',
62+
'{"id":"0da6b8a7-ccd4-4270-8058-9e30a3f55ceb","name":"Written","scheduleKey":{"type":2,"duration":2,"version":"1.0"},"language":"de","bookmark":{"dayIndex":0,"sectionIndex":-1},"withTargetDate":false,"showEvents":false,"showLocations":false}',
6363
'{"id":"2dab49f3-aecf-4aba-9e91-d75c297d4b7e","name":"Sequential","scheduleKey":{"type":1,"duration":2,"version":"1.0"},"language":"ro","bookmark":{"dayIndex":364,"sectionIndex":1},"lastDate":"2024-11-21T00:00:00.000","withTargetDate":true,"showEvents":true,"showLocations":true}',
6464
'{"id":"e37bf9df-077a-49db-adcb-d56384906103","name":"Chronological","scheduleKey":{"type":0,"duration":1,"version":"1.0"},"language":"en","bookmark":{"dayIndex":182,"sectionIndex":1},"withTargetDate":true,"showEvents":true,"showLocations":true}'
6565
];

0 commit comments

Comments
 (0)