feat(02-01): German task templates for 14 room types with detectRoomType
- Create TaskTemplate class with name, intervalType, intervalDays, effortLevel - Add roomTemplates const map with 3-6 templates per room type (14 total) - Implement detectRoomType with case-insensitive matching and alias support - Room types: kueche, badezimmer, schlafzimmer, wohnzimmer, flur, buero, garage, balkon, waschkueche, keller, kinderzimmer, gaestezimmer, esszimmer, garten - All 11 template tests passing Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
371
lib/features/templates/data/task_templates.dart
Normal file
371
lib/features/templates/data/task_templates.dart
Normal file
@@ -0,0 +1,371 @@
|
|||||||
|
import '../../tasks/domain/effort_level.dart';
|
||||||
|
import '../../tasks/domain/frequency.dart';
|
||||||
|
|
||||||
|
/// A bundled task template with German name, interval, and effort level.
|
||||||
|
class TaskTemplate {
|
||||||
|
final String name;
|
||||||
|
final String? description;
|
||||||
|
final IntervalType intervalType;
|
||||||
|
final int intervalDays;
|
||||||
|
final EffortLevel effortLevel;
|
||||||
|
|
||||||
|
const TaskTemplate({
|
||||||
|
required this.name,
|
||||||
|
this.description,
|
||||||
|
required this.intervalType,
|
||||||
|
this.intervalDays = 1,
|
||||||
|
required this.effortLevel,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// German-language task templates for all 14 room types.
|
||||||
|
///
|
||||||
|
/// Each room type has 3-6 realistic household tasks with appropriate
|
||||||
|
/// frequencies and effort levels.
|
||||||
|
const Map<String, List<TaskTemplate>> roomTemplates = {
|
||||||
|
'kueche': [
|
||||||
|
TaskTemplate(
|
||||||
|
name: 'Abspuelen',
|
||||||
|
intervalType: IntervalType.daily,
|
||||||
|
effortLevel: EffortLevel.low,
|
||||||
|
),
|
||||||
|
TaskTemplate(
|
||||||
|
name: 'Herd reinigen',
|
||||||
|
intervalType: IntervalType.weekly,
|
||||||
|
effortLevel: EffortLevel.medium,
|
||||||
|
),
|
||||||
|
TaskTemplate(
|
||||||
|
name: 'Kuehlschrank reinigen',
|
||||||
|
intervalType: IntervalType.monthly,
|
||||||
|
effortLevel: EffortLevel.medium,
|
||||||
|
),
|
||||||
|
TaskTemplate(
|
||||||
|
name: 'Backofen reinigen',
|
||||||
|
intervalType: IntervalType.monthly,
|
||||||
|
effortLevel: EffortLevel.high,
|
||||||
|
),
|
||||||
|
TaskTemplate(
|
||||||
|
name: 'Muell rausbringen',
|
||||||
|
intervalType: IntervalType.everyNDays,
|
||||||
|
intervalDays: 2,
|
||||||
|
effortLevel: EffortLevel.low,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
'badezimmer': [
|
||||||
|
TaskTemplate(
|
||||||
|
name: 'Toilette putzen',
|
||||||
|
intervalType: IntervalType.weekly,
|
||||||
|
effortLevel: EffortLevel.medium,
|
||||||
|
),
|
||||||
|
TaskTemplate(
|
||||||
|
name: 'Spiegel reinigen',
|
||||||
|
intervalType: IntervalType.weekly,
|
||||||
|
effortLevel: EffortLevel.low,
|
||||||
|
),
|
||||||
|
TaskTemplate(
|
||||||
|
name: 'Dusche reinigen',
|
||||||
|
intervalType: IntervalType.weekly,
|
||||||
|
effortLevel: EffortLevel.medium,
|
||||||
|
),
|
||||||
|
TaskTemplate(
|
||||||
|
name: 'Waschbecken reinigen',
|
||||||
|
intervalType: IntervalType.weekly,
|
||||||
|
effortLevel: EffortLevel.low,
|
||||||
|
),
|
||||||
|
TaskTemplate(
|
||||||
|
name: 'Badezimmerboden wischen',
|
||||||
|
intervalType: IntervalType.weekly,
|
||||||
|
effortLevel: EffortLevel.medium,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
'schlafzimmer': [
|
||||||
|
TaskTemplate(
|
||||||
|
name: 'Bettwasche wechseln',
|
||||||
|
intervalType: IntervalType.biweekly,
|
||||||
|
effortLevel: EffortLevel.medium,
|
||||||
|
),
|
||||||
|
TaskTemplate(
|
||||||
|
name: 'Staubsaugen',
|
||||||
|
intervalType: IntervalType.weekly,
|
||||||
|
effortLevel: EffortLevel.medium,
|
||||||
|
),
|
||||||
|
TaskTemplate(
|
||||||
|
name: 'Staub wischen',
|
||||||
|
intervalType: IntervalType.weekly,
|
||||||
|
effortLevel: EffortLevel.low,
|
||||||
|
),
|
||||||
|
TaskTemplate(
|
||||||
|
name: 'Fenster putzen',
|
||||||
|
intervalType: IntervalType.monthly,
|
||||||
|
effortLevel: EffortLevel.medium,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
'wohnzimmer': [
|
||||||
|
TaskTemplate(
|
||||||
|
name: 'Staubsaugen',
|
||||||
|
intervalType: IntervalType.weekly,
|
||||||
|
effortLevel: EffortLevel.medium,
|
||||||
|
),
|
||||||
|
TaskTemplate(
|
||||||
|
name: 'Staub wischen',
|
||||||
|
intervalType: IntervalType.weekly,
|
||||||
|
effortLevel: EffortLevel.low,
|
||||||
|
),
|
||||||
|
TaskTemplate(
|
||||||
|
name: 'Kissen aufschuetteln',
|
||||||
|
intervalType: IntervalType.daily,
|
||||||
|
effortLevel: EffortLevel.low,
|
||||||
|
),
|
||||||
|
TaskTemplate(
|
||||||
|
name: 'Fenster putzen',
|
||||||
|
intervalType: IntervalType.monthly,
|
||||||
|
effortLevel: EffortLevel.medium,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
'flur': [
|
||||||
|
TaskTemplate(
|
||||||
|
name: 'Boden wischen',
|
||||||
|
intervalType: IntervalType.weekly,
|
||||||
|
effortLevel: EffortLevel.medium,
|
||||||
|
),
|
||||||
|
TaskTemplate(
|
||||||
|
name: 'Schuhe aufraumen',
|
||||||
|
intervalType: IntervalType.weekly,
|
||||||
|
effortLevel: EffortLevel.low,
|
||||||
|
),
|
||||||
|
TaskTemplate(
|
||||||
|
name: 'Garderobe aufraeumen',
|
||||||
|
intervalType: IntervalType.monthly,
|
||||||
|
effortLevel: EffortLevel.low,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
'buero': [
|
||||||
|
TaskTemplate(
|
||||||
|
name: 'Schreibtisch aufraeumen',
|
||||||
|
intervalType: IntervalType.weekly,
|
||||||
|
effortLevel: EffortLevel.low,
|
||||||
|
),
|
||||||
|
TaskTemplate(
|
||||||
|
name: 'Staubsaugen',
|
||||||
|
intervalType: IntervalType.weekly,
|
||||||
|
effortLevel: EffortLevel.medium,
|
||||||
|
),
|
||||||
|
TaskTemplate(
|
||||||
|
name: 'Bildschirm reinigen',
|
||||||
|
intervalType: IntervalType.monthly,
|
||||||
|
effortLevel: EffortLevel.low,
|
||||||
|
),
|
||||||
|
TaskTemplate(
|
||||||
|
name: 'Papierkorb leeren',
|
||||||
|
intervalType: IntervalType.weekly,
|
||||||
|
effortLevel: EffortLevel.low,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
'garage': [
|
||||||
|
TaskTemplate(
|
||||||
|
name: 'Boden fegen',
|
||||||
|
intervalType: IntervalType.monthly,
|
||||||
|
effortLevel: EffortLevel.medium,
|
||||||
|
),
|
||||||
|
TaskTemplate(
|
||||||
|
name: 'Aufraeumen',
|
||||||
|
intervalType: IntervalType.quarterly,
|
||||||
|
effortLevel: EffortLevel.high,
|
||||||
|
),
|
||||||
|
TaskTemplate(
|
||||||
|
name: 'Werkzeug sortieren',
|
||||||
|
intervalType: IntervalType.quarterly,
|
||||||
|
effortLevel: EffortLevel.medium,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
'balkon': [
|
||||||
|
TaskTemplate(
|
||||||
|
name: 'Boden fegen',
|
||||||
|
intervalType: IntervalType.weekly,
|
||||||
|
effortLevel: EffortLevel.low,
|
||||||
|
),
|
||||||
|
TaskTemplate(
|
||||||
|
name: 'Pflanzen giessen',
|
||||||
|
intervalType: IntervalType.everyNDays,
|
||||||
|
intervalDays: 2,
|
||||||
|
effortLevel: EffortLevel.low,
|
||||||
|
),
|
||||||
|
TaskTemplate(
|
||||||
|
name: 'Gelaender reinigen',
|
||||||
|
intervalType: IntervalType.monthly,
|
||||||
|
effortLevel: EffortLevel.medium,
|
||||||
|
),
|
||||||
|
TaskTemplate(
|
||||||
|
name: 'Moebel reinigen',
|
||||||
|
intervalType: IntervalType.monthly,
|
||||||
|
effortLevel: EffortLevel.medium,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
'waschkueche': [
|
||||||
|
TaskTemplate(
|
||||||
|
name: 'Waschmaschine reinigen',
|
||||||
|
intervalType: IntervalType.monthly,
|
||||||
|
effortLevel: EffortLevel.medium,
|
||||||
|
),
|
||||||
|
TaskTemplate(
|
||||||
|
name: 'Trockner reinigen',
|
||||||
|
intervalType: IntervalType.monthly,
|
||||||
|
effortLevel: EffortLevel.medium,
|
||||||
|
),
|
||||||
|
TaskTemplate(
|
||||||
|
name: 'Boden wischen',
|
||||||
|
intervalType: IntervalType.weekly,
|
||||||
|
effortLevel: EffortLevel.medium,
|
||||||
|
),
|
||||||
|
TaskTemplate(
|
||||||
|
name: 'Waschmittel auffuellen',
|
||||||
|
intervalType: IntervalType.monthly,
|
||||||
|
effortLevel: EffortLevel.low,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
'keller': [
|
||||||
|
TaskTemplate(
|
||||||
|
name: 'Staubsaugen',
|
||||||
|
intervalType: IntervalType.monthly,
|
||||||
|
effortLevel: EffortLevel.medium,
|
||||||
|
),
|
||||||
|
TaskTemplate(
|
||||||
|
name: 'Aufraeumen',
|
||||||
|
intervalType: IntervalType.quarterly,
|
||||||
|
effortLevel: EffortLevel.high,
|
||||||
|
),
|
||||||
|
TaskTemplate(
|
||||||
|
name: 'Luftentfeuchter pruefen',
|
||||||
|
intervalType: IntervalType.monthly,
|
||||||
|
effortLevel: EffortLevel.low,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
'kinderzimmer': [
|
||||||
|
TaskTemplate(
|
||||||
|
name: 'Spielzeug aufraeumen',
|
||||||
|
intervalType: IntervalType.daily,
|
||||||
|
effortLevel: EffortLevel.low,
|
||||||
|
),
|
||||||
|
TaskTemplate(
|
||||||
|
name: 'Staubsaugen',
|
||||||
|
intervalType: IntervalType.weekly,
|
||||||
|
effortLevel: EffortLevel.medium,
|
||||||
|
),
|
||||||
|
TaskTemplate(
|
||||||
|
name: 'Bettwasche wechseln',
|
||||||
|
intervalType: IntervalType.biweekly,
|
||||||
|
effortLevel: EffortLevel.medium,
|
||||||
|
),
|
||||||
|
TaskTemplate(
|
||||||
|
name: 'Staub wischen',
|
||||||
|
intervalType: IntervalType.weekly,
|
||||||
|
effortLevel: EffortLevel.low,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
'gaestezimmer': [
|
||||||
|
TaskTemplate(
|
||||||
|
name: 'Staubsaugen',
|
||||||
|
intervalType: IntervalType.biweekly,
|
||||||
|
effortLevel: EffortLevel.medium,
|
||||||
|
),
|
||||||
|
TaskTemplate(
|
||||||
|
name: 'Bettwasche wechseln',
|
||||||
|
intervalType: IntervalType.monthly,
|
||||||
|
effortLevel: EffortLevel.medium,
|
||||||
|
),
|
||||||
|
TaskTemplate(
|
||||||
|
name: 'Staub wischen',
|
||||||
|
intervalType: IntervalType.biweekly,
|
||||||
|
effortLevel: EffortLevel.low,
|
||||||
|
),
|
||||||
|
TaskTemplate(
|
||||||
|
name: 'Lueften',
|
||||||
|
intervalType: IntervalType.weekly,
|
||||||
|
effortLevel: EffortLevel.low,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
'esszimmer': [
|
||||||
|
TaskTemplate(
|
||||||
|
name: 'Tisch abwischen',
|
||||||
|
intervalType: IntervalType.daily,
|
||||||
|
effortLevel: EffortLevel.low,
|
||||||
|
),
|
||||||
|
TaskTemplate(
|
||||||
|
name: 'Staubsaugen',
|
||||||
|
intervalType: IntervalType.weekly,
|
||||||
|
effortLevel: EffortLevel.medium,
|
||||||
|
),
|
||||||
|
TaskTemplate(
|
||||||
|
name: 'Stuehle reinigen',
|
||||||
|
intervalType: IntervalType.monthly,
|
||||||
|
effortLevel: EffortLevel.medium,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
'garten': [
|
||||||
|
TaskTemplate(
|
||||||
|
name: 'Rasen maehen',
|
||||||
|
intervalType: IntervalType.weekly,
|
||||||
|
effortLevel: EffortLevel.high,
|
||||||
|
),
|
||||||
|
TaskTemplate(
|
||||||
|
name: 'Unkraut jaeten',
|
||||||
|
intervalType: IntervalType.weekly,
|
||||||
|
effortLevel: EffortLevel.medium,
|
||||||
|
),
|
||||||
|
TaskTemplate(
|
||||||
|
name: 'Hecke schneiden',
|
||||||
|
intervalType: IntervalType.quarterly,
|
||||||
|
effortLevel: EffortLevel.high,
|
||||||
|
),
|
||||||
|
TaskTemplate(
|
||||||
|
name: 'Laub harken',
|
||||||
|
intervalType: IntervalType.weekly,
|
||||||
|
effortLevel: EffortLevel.medium,
|
||||||
|
),
|
||||||
|
TaskTemplate(
|
||||||
|
name: 'Pflanzen giessen',
|
||||||
|
intervalType: IntervalType.everyNDays,
|
||||||
|
intervalDays: 2,
|
||||||
|
effortLevel: EffortLevel.low,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Aliases for room type detection.
|
||||||
|
const Map<String, List<String>> _aliases = {
|
||||||
|
'badezimmer': ['bad', 'wc', 'toilette'],
|
||||||
|
'buero': ['arbeitszimmer', 'office'],
|
||||||
|
'waschkueche': ['waschraum'],
|
||||||
|
'garten': ['terrasse', 'aussenbereich', 'hof'],
|
||||||
|
'gaestezimmer': ['gaeste'],
|
||||||
|
'kinderzimmer': ['kinder'],
|
||||||
|
'schlafzimmer': ['schlafraum'],
|
||||||
|
'kueche': ['kitchen'],
|
||||||
|
'esszimmer': ['essbereich'],
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Detect a room type from a user-entered room name.
|
||||||
|
///
|
||||||
|
/// Performs case-insensitive matching against room type keys and their
|
||||||
|
/// aliases. Returns the room type key (e.g. "kueche") or null if no match.
|
||||||
|
String? detectRoomType(String roomName) {
|
||||||
|
final lower = roomName.toLowerCase().trim();
|
||||||
|
|
||||||
|
// Check direct room type keys first
|
||||||
|
for (final type in roomTemplates.keys) {
|
||||||
|
if (lower.contains(type)) {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check aliases
|
||||||
|
for (final entry in _aliases.entries) {
|
||||||
|
for (final alias in entry.value) {
|
||||||
|
if (lower.contains(alias)) {
|
||||||
|
return entry.key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
111
test/features/templates/task_templates_test.dart
Normal file
111
test/features/templates/task_templates_test.dart
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:household_keeper/features/tasks/domain/effort_level.dart';
|
||||||
|
import 'package:household_keeper/features/tasks/domain/frequency.dart';
|
||||||
|
import 'package:household_keeper/features/templates/data/task_templates.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
group('roomTemplates', () {
|
||||||
|
test('contains exactly 14 room type keys', () {
|
||||||
|
expect(roomTemplates.length, 14);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('all 14 room types from TMPL-02 are present', () {
|
||||||
|
const expectedTypes = [
|
||||||
|
'kueche',
|
||||||
|
'badezimmer',
|
||||||
|
'schlafzimmer',
|
||||||
|
'wohnzimmer',
|
||||||
|
'flur',
|
||||||
|
'buero',
|
||||||
|
'garage',
|
||||||
|
'balkon',
|
||||||
|
'waschkueche',
|
||||||
|
'keller',
|
||||||
|
'kinderzimmer',
|
||||||
|
'gaestezimmer',
|
||||||
|
'esszimmer',
|
||||||
|
'garten',
|
||||||
|
];
|
||||||
|
for (final type in expectedTypes) {
|
||||||
|
expect(
|
||||||
|
roomTemplates.containsKey(type),
|
||||||
|
isTrue,
|
||||||
|
reason: 'Missing room type: $type',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test('each room type maps to a non-empty list of TaskTemplate objects', () {
|
||||||
|
for (final entry in roomTemplates.entries) {
|
||||||
|
expect(
|
||||||
|
entry.value,
|
||||||
|
isNotEmpty,
|
||||||
|
reason: 'Room type ${entry.key} has no templates',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test('every TaskTemplate has a non-empty German name', () {
|
||||||
|
for (final entry in roomTemplates.entries) {
|
||||||
|
for (final template in entry.value) {
|
||||||
|
expect(
|
||||||
|
template.name.isNotEmpty,
|
||||||
|
isTrue,
|
||||||
|
reason:
|
||||||
|
'Template in ${entry.key} has empty name',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test('every TaskTemplate has a valid IntervalType', () {
|
||||||
|
for (final entry in roomTemplates.entries) {
|
||||||
|
for (final template in entry.value) {
|
||||||
|
expect(
|
||||||
|
IntervalType.values.contains(template.intervalType),
|
||||||
|
isTrue,
|
||||||
|
reason:
|
||||||
|
'Template "${template.name}" in ${entry.key} has invalid intervalType',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test('every TaskTemplate has a valid EffortLevel', () {
|
||||||
|
for (final entry in roomTemplates.entries) {
|
||||||
|
for (final template in entry.value) {
|
||||||
|
expect(
|
||||||
|
EffortLevel.values.contains(template.effortLevel),
|
||||||
|
isTrue,
|
||||||
|
reason:
|
||||||
|
'Template "${template.name}" in ${entry.key} has invalid effortLevel',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group('detectRoomType', () {
|
||||||
|
test('"Kueche" returns "kueche"', () {
|
||||||
|
expect(detectRoomType('Kueche'), 'kueche');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('"Mein Badezimmer" returns "badezimmer"', () {
|
||||||
|
expect(detectRoomType('Mein Badezimmer'), 'badezimmer');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('"Bad" returns "badezimmer" (alias)', () {
|
||||||
|
expect(detectRoomType('Bad'), 'badezimmer');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('"Random Name" returns null', () {
|
||||||
|
expect(detectRoomType('Random Name'), isNull);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('is case-insensitive', () {
|
||||||
|
expect(detectRoomType('KUECHE'), 'kueche');
|
||||||
|
expect(detectRoomType('kueche'), 'kueche');
|
||||||
|
expect(detectRoomType('Kueche'), 'kueche');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user