Skip to content

Commit

Permalink
plans: localize the name of a new plan
Browse files Browse the repository at this point in the history
  • Loading branch information
wfleischer committed Jan 6, 2025
1 parent 52f3088 commit 57974bd
Show file tree
Hide file tree
Showing 14 changed files with 76 additions and 58 deletions.
52 changes: 35 additions & 17 deletions integration_test/app_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,17 @@ import 'package:flutter/scheduler.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:nwt_reading/src/base/presentation/plan.dart';
import 'package:nwt_reading/src/base/repositories/shared_preferences_repository.dart';
import 'package:nwt_reading/src/bible_languages/entities/bible_languages.dart';

import 'package:nwt_reading/src/bible_languages/repositories/bible_languages_repository.dart';
import 'package:nwt_reading/src/plans/entities/plan.dart';
import 'package:nwt_reading/src/plans/entities/plans.dart';
import 'package:nwt_reading/src/plans/presentations/plan_card.dart';
import 'package:nwt_reading/src/plans/presentations/plan_name_tile.dart';
import 'package:nwt_reading/src/plans/repositories/plans_repository.dart';
import 'package:nwt_reading/src/plans/stories/plan_edit_story.dart';
import 'package:nwt_reading/src/schedules/entities/events.dart';
import 'package:nwt_reading/src/schedules/entities/locations.dart';
import 'package:nwt_reading/src/schedules/entities/schedule.dart';
Expand Down Expand Up @@ -129,20 +132,27 @@ void main() async {
await tester.pumpAndSettle();
await takeScreenshot(tester: tester, binding: binding, filename: 'new');

expect(providerContainer.read(plansProvider).plans.length, 0);
BuildContext buildContext =
tester.firstElement(find.byKey(const Key('plan-name')));
TextFormField nameTextFormField =
tester.firstWidget(find.byKey(const Key('plan-name')));
String? planId =
(tester.firstWidget(find.byKey(const Key('plan-name-tile')))
as PlanNameTile)
.planId;
expect(
(tester.firstWidget(find.byKey(const Key('plan-name')))
as TextFormField)
.controller
?.text,
'Chronological y1');
nameTextFormField.controller?.text,
getPlanName(buildContext,
providerContainer.read(planEditProviderFamily(planId))));
expect(providerContainer.read(plansProvider).plans.length, 0);
expect(find.byKey(const Key('target-status')), findsNothing);

await tester.tap(find.byIcon(Icons.done));
await tester.pumpAndSettle();

var plan = providerContainer.read(plansProvider).plans.first;
expect(plan.name, 'Chronological y1');
Plan plan = providerContainer.read(plansProvider).plans.first;
buildContext = tester.element(find.byKey(const Key('plans-grid')));
expect(plan.name, null);
expect(plan.scheduleKey.type, ScheduleType.chronological);
expect(plan.scheduleKey.duration, ScheduleDuration.y1);
expect(plan.scheduleKey.version, '1.0');
Expand All @@ -165,12 +175,16 @@ void main() async {
.last);
await tester.pumpAndSettle();

buildContext = tester.firstElement(find.byKey(const Key('plan-name')));
nameTextFormField =
tester.firstWidget(find.byKey(const Key('plan-name'))) as TextFormField;
planId = (tester.firstWidget(find.byKey(const Key('plan-name-tile')))
as PlanNameTile)
.planId;
expect(
(tester.firstWidget(find.byKey(const Key('plan-name')))
as TextFormField)
.controller
?.text,
'Canonical y4');
nameTextFormField.controller?.text,
getPlanName(buildContext,
providerContainer.read(planEditProviderFamily(planId))));

final firstBibleLanguageKey = providerContainer
.read(bibleLanguagesProvider)
Expand Down Expand Up @@ -721,12 +735,15 @@ void main() async {
await tester.pumpAndSettle();
await takeScreenshot(tester: tester, binding: binding, filename: 'edit');

Plan plan = providerContainer.read(plansProvider).plans.first;
BuildContext buildContext =
tester.firstElement(find.byKey(const Key('plan-name')));
expect(
(tester.firstWidget(find.byKey(const Key('plan-name')))
as TextFormField)
.controller
?.text,
'Chronological y1');
getPlanName(buildContext, plan));

await tester.tap(find
.descendant(
Expand All @@ -740,13 +757,14 @@ void main() async {
as TextFormField)
.controller
?.text,
'Chronological y4');
getPlanName(buildContext,
providerContainer.read(planEditProviderFamily(plan.id))));

await tester.enterText(find.byKey(const Key('plan-name')), 'Test 😃');
await tester.pumpAndSettle();

var plan = providerContainer.read(plansProvider).plans.first;
expect(plan.name, 'Chronological y1');
plan = providerContainer.read(plansProvider).plans.first;
expect(plan.name, null);

await tester.tap(find.byIcon(Icons.done));
await tester.pumpAndSettle();
Expand Down
22 changes: 22 additions & 0 deletions lib/src/base/presentation/plan.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:nwt_reading/src/localization/app_localizations_getter.dart';
import 'package:nwt_reading/src/plans/entities/plan.dart';
import 'package:nwt_reading/src/schedules/entities/schedule.dart';

String getPlanName(BuildContext context, Plan plan) =>
plan.name ??
'${toBeginningOfSentenceCase(
switch (plan.scheduleKey.type) {
ScheduleType.chronological =>
context.loc.planEditPageChronologicalLabel,
ScheduleType.canonical => context.loc.planEditPageCanonicalLabel,
ScheduleType.written => context.loc.planEditPageAsWrittenLabel,
},
)} ${switch (plan.scheduleKey.duration) {
ScheduleDuration.m3 => context.loc.planEditPageMonthsLabel(3),
ScheduleDuration.m6 => context.loc.planEditPageMonthsLabel(6),
ScheduleDuration.y1 => context.loc.planEditPageYearsLabel(1),
ScheduleDuration.y2 => context.loc.planEditPageYearsLabel(2),
ScheduleDuration.y4 => context.loc.planEditPageYearsLabel(4),
}}';
4 changes: 2 additions & 2 deletions lib/src/plans/entities/plan.dart
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ class TogglingTooManyDaysException implements Exception {}
class Plan extends Equatable {
const Plan({
required this.id,
required this.name,
this.name,
required this.scheduleKey,
required this.language,
required this.bookmark,
Expand All @@ -146,7 +146,7 @@ class Plan extends Equatable {
});

final String id;
final String name;
final String? name;
final ScheduleKey scheduleKey;
final String language;
final Bookmark bookmark;
Expand Down
6 changes: 0 additions & 6 deletions lib/src/plans/entities/plans.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:intl/intl.dart';
import 'package:nwt_reading/src/plans/entities/plan.dart';
import 'package:nwt_reading/src/schedules/entities/schedule.dart';
import 'package:uuid/uuid.dart';
Expand All @@ -22,19 +21,14 @@ class PlansNotifier extends Notifier<Plans> {

String getNewPlanId() => _uuid.v4();

String getDefaultName(ScheduleKey scheduleKey) =>
'${toBeginningOfSentenceCase(scheduleKey.type.name)} ${scheduleKey.duration.name}';

Plan getNewPlan(String planId) {
const scheduleKey = ScheduleKey(
type: ScheduleType.chronological,
duration: ScheduleDuration.y1,
version: '1.0');
final name = getDefaultName(scheduleKey);

return Plan(
id: planId,
name: name,
scheduleKey: scheduleKey,
language: 'en',
bookmark: const Bookmark(dayIndex: 0, sectionIndex: -1),
Expand Down
3 changes: 2 additions & 1 deletion lib/src/plans/presentations/plan_card.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:nwt_reading/src/base/presentation/plan.dart';
import 'package:nwt_reading/src/localization/app_localizations_getter.dart';
import 'package:nwt_reading/src/plans/entities/plan.dart';
import 'package:nwt_reading/src/schedules/entities/schedule.dart';
Expand Down Expand Up @@ -41,7 +42,7 @@ class PlanCard extends ConsumerWidget {
],
),
Text(
plan.name,
getPlanName(context, plan),
style: Theme.of(context)
.textTheme
.headlineMedium
Expand Down
2 changes: 1 addition & 1 deletion lib/src/plans/presentations/plan_edit_dialog.dart
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class PlanEditDialog extends ConsumerWidget {
}
})
]),
PlanNameTile(planId),
PlanNameTile(planId, key: const Key('plan-name-tile')),
const SizedBox(height: 20),
if (isNewPlan) PlanTypeSegmentedButton(planId),
if (isNewPlan) const SizedBox(height: 20),
Expand Down
13 changes: 5 additions & 8 deletions lib/src/plans/presentations/plan_name_tile.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:nwt_reading/src/base/presentation/plan.dart';
import 'package:nwt_reading/src/plans/stories/plan_edit_story.dart';

class PlanNameTile extends ConsumerWidget {
Expand All @@ -10,23 +11,19 @@ class PlanNameTile extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final plan = ref.watch(planEditProviderFamily(planId));
final planName = getPlanName(context, plan);
final planEdit = ref.read(planEditProviderFamily(planId).notifier);

return ListTile(
title: TextFormField(
key: const Key('plan-name'),
autofillHints: const ['plan-name'],
autofocus: true,
controller: TextEditingController(text: plan.name),
controller: TextEditingController(text: planName),
decoration:
const InputDecoration(hintText: 'Enter a name for your reading plan'),
onChanged: (name) => planEdit.changeName(name),
validator: (name) {
if (name == null || name.isEmpty) {
return 'Please enter a name';
}
return null;
},
onChanged: (name) =>
(name != planName) ? planEdit.changeName(name) : null,
));
}
}
4 changes: 3 additions & 1 deletion lib/src/plans/presentations/plans_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,9 @@ class PlansPageState extends ConsumerState<PlansPage> {
),
],
),
body: PlansGrid(),
body: PlansGrid(
key: const Key('plans-grid'),
),
floatingActionButton: FloatingActionButton(
tooltip: context.loc.plansPageAddPlanTooltip,
onPressed: () => showDialog<String>(
Expand Down
2 changes: 1 addition & 1 deletion lib/src/plans/repositories/plans_deserializer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class PlansDeserializer {

Plan _convertMapToPlan(Map<String, dynamic> planMap) {
final id = planMap['id'] as String;
final name = planMap['name'] as String;
final name = planMap['name'] == null ? null : planMap['name'] as String;
final schedule =
convertMapToScheduleKey(planMap['scheduleKey'] as Map<String, dynamic>);
final language = planMap['language'] as String;
Expand Down
1 change: 0 additions & 1 deletion lib/src/plans/repositories/plans_repository.dart
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,6 @@ class PlansRepository {
plans = Plans([
Plan(
id: _uuid.v4(),
name: plansNotifier.getDefaultName(scheduleKey),
scheduleKey: scheduleKey,
language: readingLanguage ?? language ?? 'en',
bookmark: bookmark,
Expand Down
2 changes: 1 addition & 1 deletion lib/src/plans/repositories/plans_serializer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class PlansSerializer {

Map<String, dynamic> _convertPlanToMap(Plan plan) => {
'id': plan.id,
'name': plan.name,
if (plan.name != null) 'name': plan.name,
'scheduleKey': _convertScheduleKeyToMap(plan.scheduleKey),
'language': plan.language,
'bookmark': _convertBookmarkToMap(plan.bookmark),
Expand Down
12 changes: 0 additions & 12 deletions lib/src/plans/stories/plan_edit_story.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,6 @@ class PlanEdit extends AutoDisposeFamilyNotifier<Plan, String?> {

void changeName(String name) => _name = name;

void updateDefaultName(ScheduleKey scheduleKey) {
final plansNotifier = ref.read(plansProvider.notifier);
final isDefaultName = _name == null ||
_name == plansNotifier.getDefaultName(state.scheduleKey);

if (isDefaultName) {
_name = plansNotifier.getDefaultName(scheduleKey);
}
}

void updateLanguage(String language) {
if (language != state.language) {
state = state.copyWith(language: language);
Expand All @@ -54,7 +44,6 @@ class PlanEdit extends AutoDisposeFamilyNotifier<Plan, String?> {
final newDayIndex =
(state.bookmark.dayIndex * newScheduleLength / oldScheduleLength)
.round();
updateDefaultName(newScheduleKey);

state = state.copyWith(
name: _name,
Expand All @@ -70,7 +59,6 @@ class PlanEdit extends AutoDisposeFamilyNotifier<Plan, String?> {
void updateScheduleType(ScheduleType scheduleType) {
if (scheduleType != state.scheduleKey.type) {
final newScheduleKey = state.scheduleKey.copyWith(type: scheduleType);
updateDefaultName(newScheduleKey);

state = state.copyWith(
name: _name,
Expand Down
5 changes: 3 additions & 2 deletions lib/src/schedules/presentations/schedule_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'dart:math';

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:nwt_reading/src/base/presentation/plan.dart';
import 'package:nwt_reading/src/localization/app_localizations_getter.dart';
import 'package:nwt_reading/src/plans/entities/plan.dart';
import 'package:nwt_reading/src/plans/presentations/plan_edit_dialog.dart';
Expand Down Expand Up @@ -112,12 +113,12 @@ class _SchedulePageState extends ConsumerState<SchedulePage> {
return Scaffold(
appBar: AppBar(
title: deviationDays == 0
? Text(plan.name)
? Text(getPlanName(context, plan))
: Badge(
label: Text('${deviationDays.abs()}'),
backgroundColor: badgeColor,
offset: Offset(23, -5),
child: Text(plan.name),
child: Text(getPlanName(context, plan)),
),
actions: [
IconButton(
Expand Down
6 changes: 1 addition & 5 deletions test/test_data.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ Future<Map<String, String>> getWhatsNewSeenPreference() async => {
final Plans testPlans = Plans([
Plan(
id: '5aa4de9e-036b-42cd-8bcb-a92cae46db27',
name: 'Chronological y1',
scheduleKey: ScheduleKey(
type: ScheduleType.chronological,
duration: ScheduleDuration.y1,
Expand Down Expand Up @@ -66,7 +65,7 @@ final Plans testPlans = Plans([
]);

const List<String> testPlansSerialized = [
'{"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}',
'{"id":"5aa4de9e-036b-42cd-8bcb-a92cae46db27","scheduleKey":{"type":0,"duration":2,"version":"1.0"},"language":"en","bookmark":{"dayIndex":75,"sectionIndex":0},"withTargetDate":true,"showEvents":true,"showLocations":true}',
'{"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}',
'{"id":"2dab49f3-aecf-4aba-9e91-d75c297d4b7e","name":"Canonical","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}',
'{"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}'
Expand Down Expand Up @@ -100,7 +99,6 @@ final List<LegacyExport> testLegacyExports = [
plans: Plans(const [
Plan(
id: '',
name: 'Canonical y1',
scheduleKey: ScheduleKey(
type: ScheduleType.canonical,
duration: ScheduleDuration.y1,
Expand All @@ -119,7 +117,6 @@ final List<LegacyExport> testLegacyExports = [
plans: Plans([
Plan(
id: '',
name: 'Chronological y1',
scheduleKey: const ScheduleKey(
type: ScheduleType.chronological,
duration: ScheduleDuration.y1,
Expand All @@ -139,7 +136,6 @@ final List<LegacyExport> testLegacyExports = [
plans: Plans([
Plan(
id: '3266e6fd-ce74-48f0-a491-da086a7704c7',
name: 'Chronological y1',
scheduleKey: const ScheduleKey(
type: ScheduleType.chronological,
duration: ScheduleDuration.y1,
Expand Down

0 comments on commit 57974bd

Please sign in to comment.