diff --git a/.gitea/workflows/release.yaml b/.gitea/workflows/release.yaml
new file mode 100644
index 0000000..f21a3ff
--- /dev/null
+++ b/.gitea/workflows/release.yaml
@@ -0,0 +1,86 @@
+name: Build and Release to F-Droid
+
+on:
+ push:
+ tags:
+ - 'v*'
+
+jobs:
+ build-and-deploy:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Setup Java
+ uses: actions/setup-java@v4
+ with:
+ distribution: 'zulu'
+ java-version: '17'
+
+ - name: Setup Flutter
+ uses: subosito/flutter-action@v2
+ with:
+ flutter-version: '3.11.0'
+ channel: 'stable'
+
+ - name: Install dependencies
+ run: flutter pub get
+
+ # ADD THIS NEW STEP
+ - name: Setup Android Keystore
+ env:
+ KEYSTORE_BASE64: ${{ secrets.KEYSTORE_BASE64 }}
+ KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
+ KEY_ALIAS: ${{ secrets.KEY_ALIAS }}
+ run: |
+ # Decode the base64 string back into the binary .jks file
+ echo "$KEYSTORE_BASE64" | base64 --decode > android/app/upload-keystore.jks
+
+ # Create the key.properties file that build.gradle expects
+ echo "storePassword=$KEY_PASSWORD" > android/key.properties
+ echo "keyPassword=$KEY_PASSWORD" >> android/key.properties
+ echo "keyAlias=$KEY_ALIAS" >> android/key.properties
+ echo "storeFile=upload-keystore.jks" >> android/key.properties
+
+ - name: Build APK
+ run: flutter build apk --release
+
+ - name: Setup F-Droid Server Tools
+ run: |
+ sudo apt-get update
+ sudo apt-get install -y fdroidserver sshpass
+
+ - name: Initialize or fetch F-Droid Repository
+ env:
+ HOST: ${{ secrets.HETZNER_HOST }}
+ USER: ${{ secrets.HETZNER_USER }}
+ PASS: ${{ secrets.HETZNER_PASS }}
+ run: |
+ mkdir -p fdroid
+ cd fdroid
+
+ # Try to download the existing repo/ folder from Hetzner to keep older versions and the keystore
+ # If it fails (first time), we just initialize a new one
+ sshpass -p "$PASS" scp -o StrictHostKeyChecking=no -r $USER@$HOST:dev/fdroid/repo . || fdroid init
+
+ - name: Copy new APK to repo
+ run: |
+ # The app-release.apk name should ideally include the version number
+ # so it doesn't overwrite older versions in the repo.
+ VERSION_TAG=${GITHUB_REF#refs/tags/} # gets 'v1.0.0'
+ cp build/app/outputs/flutter-apk/app-release.apk fdroid/repo/my_flutter_app_${VERSION_TAG}.apk
+
+ - name: Generate F-Droid Index
+ run: |
+ cd fdroid
+ fdroid update -c
+
+ - name: Upload Repo to Hetzner
+ env:
+ HOST: ${{ secrets.HETZNER_HOST }}
+ USER: ${{ secrets.HETZNER_USER }}
+ PASS: ${{ secrets.HETZNER_PASS }}
+ run: |
+ # Use rsync to efficiently upload only the changed files (the new APK and updated index files)
+ sshpass -p "$PASS" rsync -avz -e "ssh -o StrictHostKeyChecking=no" fdroid/repo/ $USER@$HOST:dev/fdroid/repo/
diff --git a/.gitignore b/.gitignore
index 8b26114..5eb6816 100644
--- a/.gitignore
+++ b/.gitignore
@@ -118,3 +118,5 @@ app.*.symbols
!**/ios/**/default.perspectivev3
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
!/dev/ci/**/Gemfile.lock
+
+.idea
\ No newline at end of file
diff --git a/.planning/config.json b/.planning/config.json
index 8286c6c..bdd5e98 100644
--- a/.planning/config.json
+++ b/.planning/config.json
@@ -3,11 +3,16 @@
"granularity": "coarse",
"parallelization": true,
"commit_docs": true,
- "model_profile": "quality",
+ "model_profile": "balanced",
"workflow": {
"research": true,
"plan_check": true,
"verifier": true,
- "nyquist_validation": true
+ "nyquist_validation": true,
+ "auto_advance": true,
+ "_auto_chain_active": true
+ },
+ "git": {
+ "branching_strategy": "none"
}
-}
+}
\ No newline at end of file
diff --git a/.planning/phases/02-rooms-and-tasks/2-CONTEXT.md b/.planning/phases/02-rooms-and-tasks/2-CONTEXT.md
new file mode 100644
index 0000000..d40724f
--- /dev/null
+++ b/.planning/phases/02-rooms-and-tasks/2-CONTEXT.md
@@ -0,0 +1,117 @@
+# Phase 2: Rooms and Tasks - Context
+
+**Gathered:** 2026-03-15
+**Status:** Ready for planning
+
+
+## Phase Boundary
+
+Users can create and manage rooms and tasks, mark tasks done, and trust the app to schedule the next occurrence automatically. Delivers: room CRUD with icons and reorder, task CRUD with frequency intervals and effort levels, task completion with auto-scheduling, bundled German-language task templates for 14 room types, overdue highlighting, and room cards with cleanliness indicators.
+
+Requirements: ROOM-01, ROOM-02, ROOM-03, ROOM-04, ROOM-05, TASK-01, TASK-02, TASK-03, TASK-04, TASK-05, TASK-06, TASK-07, TASK-08, TMPL-01, TMPL-02
+
+
+
+
+## Implementation Decisions
+
+### Room cards & layout
+- **2-column grid** layout on the Rooms screen — compact cards, shows more rooms at once
+- Each card shows: **room icon, room name, count of due/overdue tasks, thin cleanliness progress bar**
+- No next-task preview or total task count on cards — keep them clean
+- **Cleanliness indicator**: thin horizontal progress bar at bottom of card, fill color shifts green→yellow→red based on ratio of on-time to overdue tasks
+- **Icon picker**: curated grid of ~20-30 hand-picked household Material Icons in a bottom sheet. No full icon search — focused and simple
+- Cards support drag-and-drop reorder (ROOM-04)
+- Delete room with confirmation dialog that warns about cascade deletion of all tasks (ROOM-03)
+
+### Task completion & overdue
+- **Leading checkbox** on each task row to mark done — tap to toggle. No swipe gesture.
+- Tapping the task row (not the checkbox) opens task detail/edit
+- **Overdue visual**: due date text turns warm red/coral color. Rest of row stays normal — subtle but clear
+- **No undo** on completion — immediate and final. Records timestamp, auto-calculates next due date
+- **Task row info**: task name, relative due date (e.g. "Heute", "in 3 Tagen", "Überfällig"), and frequency label (e.g. "Wöchentlich", "Alle 3 Tage"). No effort indicator or description preview on list view
+- Tasks within a room sorted by due date (default sort order, TASK-06)
+
+### Template selection flow
+- **Post-creation prompt**: user creates a room first (name + icon), then gets prompted "Aufgaben aus Vorlagen hinzufügen?" with template selection
+- **Room type is optional** — used only to determine which templates to suggest. Not stored as a permanent field. If no matching room type is detected, no template prompt appears
+- **All templates unchecked** by default — user explicitly checks what they want. No pre-selection
+- Users can create fully custom rooms (name + icon only) with no template prompt if no room type matches
+- Templates cover all 14 room types from TMPL-02: Küche, Badezimmer, Schlafzimmer, Wohnzimmer, Flur, Büro, Garage, Balkon, Waschküche, Keller, Kinderzimmer, Gästezimmer, Esszimmer, Garten/Außenbereich
+- Templates are bundled in the app as static data (German language)
+
+### Scheduling & recurrence
+- **Two interval categories** with different behavior:
+ - **Day-count intervals** (daily, every N days, weekly, biweekly): add N days from due date. Pure arithmetic, no clamping.
+ - **Calendar-anchored intervals** (monthly, quarterly, every N months, yearly): anchor to original day-of-month. If the month is shorter, clamp to last day of month but remember the anchor (e.g. task set for the 31st: Jan 31 → Feb 28 → Mar 31)
+- **Next due calculated from original due date**, not completion date — keeps rhythm stable even when completed late
+- **Catch-up on very late completion**: if calculated next due is in the past, keep adding intervals until next due is today or in the future. No stacking of missed occurrences
+- **Custom intervals**: user picks a number + unit (Tage/Wochen/Monate). E.g. "Alle 10 Tage" or "Alle 3 Monate"
+- **Preset intervals** from TASK-04: daily, every 2 days, every 3 days, weekly, biweekly, monthly, every 2 months, quarterly, every 6 months, yearly, custom
+- All due dates stored as date-only (calendar day) — established in Phase 1 pre-decision
+
+### Claude's Discretion
+- Room creation form layout (full screen vs bottom sheet vs dialog)
+- Task creation/edit form layout and field ordering
+- Exact Material Icons chosen for the curated icon picker set
+- Drag-and-drop reorder implementation approach (ReorderableListView vs custom)
+- Delete confirmation dialog design
+- Animation on task completion (checkbox fill, row transition)
+- Template data structure and storage format (Dart constants vs JSON asset)
+- Exact color values for overdue red/coral (within the sage & stone palette)
+- Empty state design for rooms with no tasks (following Phase 1 playful tone)
+
+
+
+
+## Specific Ideas
+
+- Room type detection for templates should be lightweight — match room name against known types, don't force a classification step
+- The template prompt after room creation should feel like a helpful suggestion, not a required step — easy to dismiss
+- Overdue text color should be warm (coral/terracotta) not harsh alarm-red — fits the calm sage & stone palette
+- Relative due date labels in German: "Heute", "Morgen", "in X Tagen", "Überfällig seit X Tagen"
+- The cleanliness bar should be subtle — thin, at the bottom edge of the card, not a dominant visual element
+- Checkbox interaction should feel instant — no loading spinners, optimistic UI
+
+
+
+
+## Existing Code Insights
+
+### Reusable Assets
+- `AppDatabase` (`lib/core/database/database.dart`): Drift database with schema v1, currently no tables — Phase 2 adds Room, Task, and TaskCompletion tables
+- `appDatabaseProvider` (`lib/core/providers/database_provider.dart`): Riverpod provider with `keepAlive: true` and `ref.onDispose(db.close)` — all DAOs will reference this
+- `ThemeNotifier` pattern (`lib/core/theme/theme_provider.dart`): AsyncNotifier with SharedPreferences persistence — template for room/task notifiers
+- `SettingsScreen` (`lib/features/settings/presentation/settings_screen.dart`): ConsumerWidget with `ref.watch` + `ref.read(...notifier)` pattern — template for reactive screens
+- `RoomsScreen` placeholder (`lib/features/rooms/presentation/rooms_screen.dart`): Ready to replace with actual room grid
+- `app_de.arb` (`lib/l10n/app_de.arb`): Localization file with 18 existing keys — Phase 2 adds room/task/frequency/effort strings
+
+### Established Patterns
+- **Riverpod 3 code generation**: `@riverpod` annotation + `.g.dart` files via build_runner. Functional providers for reads, class-based AsyncNotifier for mutations
+- **Clean architecture**: `features/X/data/domain/presentation` layer structure. Presentation never imports directly from data layer
+- **GoRouter StatefulShellRoute**: `/rooms` branch exists, ready for nested routes (`/rooms/:roomId`, `/rooms/:roomId/tasks/new`)
+- **Material 3 theming**: `ColorScheme.fromSeed` with sage green seed (0xFF7A9A6D), warm stone surfaces. All color via `Theme.of(context).colorScheme`
+- **Localization**: ARB-based, German-only, strongly typed `AppLocalizations.of(context).keyName`
+- **Database testing**: `NativeDatabase.memory()` for in-memory tests, `setUp/tearDown` pattern
+- **Widget testing**: `ProviderScope` + `MaterialApp.router` with German locale
+
+### Integration Points
+- Phase 2 replaces the `RoomsScreen` placeholder with the actual room grid
+- Room cards link to room detail screens via GoRouter nested routes under `/rooms`
+- Task completion data feeds Phase 3's daily plan view (overdue/today/upcoming grouping)
+- Cleanliness indicator logic established here is reused by Phase 3 room cards on the Home screen
+- Phase 4 notifications query task due dates established in this phase's schema
+
+
+
+
+## Deferred Ideas
+
+None — discussion stayed within phase scope
+
+
+
+---
+
+*Phase: 02-rooms-and-tasks*
+*Context gathered: 2026-03-15*
diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts
index 839716f..63ede81 100644
--- a/android/app/build.gradle.kts
+++ b/android/app/build.gradle.kts
@@ -6,8 +6,8 @@ plugins {
}
android {
- namespace = "com.jlmak.household_keeper"
- compileSdk = 35
+ namespace = "de.jeanlucmakiola.household_keeper"
+ compileSdk = 36
ndkVersion = flutter.ndkVersion
compileOptions {
@@ -22,7 +22,7 @@ android {
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
- applicationId = "com.jlmak.household_keeper"
+ applicationId = "de.jeanlucmakiola.household_keeper"
// You can update the following values to match your application needs.
// For more information, see: https://flutter.dev/to/review-gradle-config.
minSdk = flutter.minSdkVersion
@@ -31,11 +31,25 @@ android {
versionName = flutter.versionName
}
+ def keystorePropertiesFile = rootProject.file("key.properties")
+ def keystoreProperties = new Properties()
+ if (keystorePropertiesFile.exists()) {
+ keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
+ }
+
+ signingConfigs {
+ release {
+ keyAlias = keystoreProperties['keyAlias']
+ keyPassword = keystoreProperties['keyPassword']
+ storeFile = keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
+ storePassword = keystoreProperties['storePassword']
+ }
+ }
buildTypes {
release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
- signingConfig = signingConfigs.getByName("debug")
+ signingConfig = signingConfigs.release
}
}
}
diff --git a/household_keeper.iml b/household_keeper.iml
new file mode 100644
index 0000000..4d723b3
--- /dev/null
+++ b/household_keeper.iml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lib/main.dart b/lib/main.dart
index 4685db9..fec7090 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -10,8 +10,8 @@ import 'package:household_keeper/core/notifications/notification_service.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
tz.initializeTimeZones();
- final timeZoneName = await FlutterTimezone.getLocalTimezone();
- tz.setLocalLocation(tz.getLocation(timeZoneName));
+ final timeZone = await FlutterTimezone.getLocalTimezone();
+ tz.setLocalLocation(tz.getLocation(timeZone.identifier));
await NotificationService().initialize();
runApp(const ProviderScope(child: App()));
}
diff --git a/pubspec.yaml b/pubspec.yaml
index 9b4d372..315391e 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -22,7 +22,7 @@ dependencies:
flutter_reorderable_grid_view: ^5.6.0
flutter_local_notifications: ^21.0.0
timezone: ^0.11.0
- flutter_timezone: ^1.0.8
+ flutter_timezone: ^5.0.2
dev_dependencies:
flutter_test:
diff --git a/test/drift/household_keeper/generated/schema.dart b/test/drift/household_keeper/generated/schema.dart
new file mode 100644
index 0000000..f5e870e
--- /dev/null
+++ b/test/drift/household_keeper/generated/schema.dart
@@ -0,0 +1,24 @@
+// dart format width=80
+// GENERATED BY drift_dev, DO NOT MODIFY.
+// ignore_for_file: type=lint,unused_import
+//
+import 'package:drift/drift.dart';
+import 'package:drift/internal/migrations.dart';
+import 'schema_v1.dart' as v1;
+import 'schema_v2.dart' as v2;
+
+class GeneratedHelper implements SchemaInstantiationHelper {
+ @override
+ GeneratedDatabase databaseForVersion(QueryExecutor db, int version) {
+ switch (version) {
+ case 1:
+ return v1.DatabaseAtV1(db);
+ case 2:
+ return v2.DatabaseAtV2(db);
+ default:
+ throw MissingSchemaException(version, versions);
+ }
+ }
+
+ static const versions = const [1, 2];
+}
diff --git a/test/drift/household_keeper/generated/schema_v1.dart b/test/drift/household_keeper/generated/schema_v1.dart
new file mode 100644
index 0000000..b3dc862
--- /dev/null
+++ b/test/drift/household_keeper/generated/schema_v1.dart
@@ -0,0 +1,16 @@
+// dart format width=80
+// GENERATED BY drift_dev, DO NOT MODIFY.
+// ignore_for_file: type=lint,unused_import
+//
+import 'package:drift/drift.dart';
+
+class DatabaseAtV1 extends GeneratedDatabase {
+ DatabaseAtV1(QueryExecutor e) : super(e);
+ @override
+ Iterable> get allTables =>
+ allSchemaEntities.whereType>();
+ @override
+ List get allSchemaEntities => [];
+ @override
+ int get schemaVersion => 1;
+}
diff --git a/test/drift/household_keeper/generated/schema_v2.dart b/test/drift/household_keeper/generated/schema_v2.dart
new file mode 100644
index 0000000..c65fd8d
--- /dev/null
+++ b/test/drift/household_keeper/generated/schema_v2.dart
@@ -0,0 +1,1034 @@
+// dart format width=80
+// GENERATED BY drift_dev, DO NOT MODIFY.
+// ignore_for_file: type=lint,unused_import
+//
+import 'package:drift/drift.dart';
+
+class Rooms extends Table with TableInfo {
+ @override
+ final GeneratedDatabase attachedDatabase;
+ final String? _alias;
+ Rooms(this.attachedDatabase, [this._alias]);
+ late final GeneratedColumn id = GeneratedColumn(
+ 'id',
+ aliasedName,
+ false,
+ hasAutoIncrement: true,
+ type: DriftSqlType.int,
+ requiredDuringInsert: false,
+ $customConstraints: 'NOT NULL PRIMARY KEY AUTOINCREMENT',
+ );
+ late final GeneratedColumn name = GeneratedColumn(
+ 'name',
+ aliasedName,
+ false,
+ type: DriftSqlType.string,
+ requiredDuringInsert: true,
+ $customConstraints: 'NOT NULL',
+ );
+ late final GeneratedColumn iconName = GeneratedColumn(
+ 'icon_name',
+ aliasedName,
+ false,
+ type: DriftSqlType.string,
+ requiredDuringInsert: true,
+ $customConstraints: 'NOT NULL',
+ );
+ late final GeneratedColumn sortOrder = GeneratedColumn(
+ 'sort_order',
+ aliasedName,
+ false,
+ type: DriftSqlType.int,
+ requiredDuringInsert: false,
+ $customConstraints: 'NOT NULL DEFAULT 0',
+ defaultValue: const CustomExpression('0'),
+ );
+ late final GeneratedColumn createdAt = GeneratedColumn(
+ 'created_at',
+ aliasedName,
+ false,
+ type: DriftSqlType.int,
+ requiredDuringInsert: true,
+ $customConstraints: 'NOT NULL',
+ );
+ @override
+ List get $columns => [
+ id,
+ name,
+ iconName,
+ sortOrder,
+ createdAt,
+ ];
+ @override
+ String get aliasedName => _alias ?? actualTableName;
+ @override
+ String get actualTableName => $name;
+ static const String $name = 'rooms';
+ @override
+ Set get $primaryKey => {id};
+ @override
+ RoomsData map(Map data, {String? tablePrefix}) {
+ final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
+ return RoomsData(
+ id: attachedDatabase.typeMapping.read(
+ DriftSqlType.int,
+ data['${effectivePrefix}id'],
+ )!,
+ name: attachedDatabase.typeMapping.read(
+ DriftSqlType.string,
+ data['${effectivePrefix}name'],
+ )!,
+ iconName: attachedDatabase.typeMapping.read(
+ DriftSqlType.string,
+ data['${effectivePrefix}icon_name'],
+ )!,
+ sortOrder: attachedDatabase.typeMapping.read(
+ DriftSqlType.int,
+ data['${effectivePrefix}sort_order'],
+ )!,
+ createdAt: attachedDatabase.typeMapping.read(
+ DriftSqlType.int,
+ data['${effectivePrefix}created_at'],
+ )!,
+ );
+ }
+
+ @override
+ Rooms createAlias(String alias) {
+ return Rooms(attachedDatabase, alias);
+ }
+
+ @override
+ bool get dontWriteConstraints => true;
+}
+
+class RoomsData extends DataClass implements Insertable {
+ final int id;
+ final String name;
+ final String iconName;
+ final int sortOrder;
+ final int createdAt;
+ const RoomsData({
+ required this.id,
+ required this.name,
+ required this.iconName,
+ required this.sortOrder,
+ required this.createdAt,
+ });
+ @override
+ Map toColumns(bool nullToAbsent) {
+ final map = {};
+ map['id'] = Variable(id);
+ map['name'] = Variable(name);
+ map['icon_name'] = Variable(iconName);
+ map['sort_order'] = Variable(sortOrder);
+ map['created_at'] = Variable(createdAt);
+ return map;
+ }
+
+ RoomsCompanion toCompanion(bool nullToAbsent) {
+ return RoomsCompanion(
+ id: Value(id),
+ name: Value(name),
+ iconName: Value(iconName),
+ sortOrder: Value(sortOrder),
+ createdAt: Value(createdAt),
+ );
+ }
+
+ factory RoomsData.fromJson(
+ Map json, {
+ ValueSerializer? serializer,
+ }) {
+ serializer ??= driftRuntimeOptions.defaultSerializer;
+ return RoomsData(
+ id: serializer.fromJson(json['id']),
+ name: serializer.fromJson(json['name']),
+ iconName: serializer.fromJson(json['iconName']),
+ sortOrder: serializer.fromJson(json['sortOrder']),
+ createdAt: serializer.fromJson(json['createdAt']),
+ );
+ }
+ @override
+ Map toJson({ValueSerializer? serializer}) {
+ serializer ??= driftRuntimeOptions.defaultSerializer;
+ return {
+ 'id': serializer.toJson(id),
+ 'name': serializer.toJson(name),
+ 'iconName': serializer.toJson(iconName),
+ 'sortOrder': serializer.toJson(sortOrder),
+ 'createdAt': serializer.toJson(createdAt),
+ };
+ }
+
+ RoomsData copyWith({
+ int? id,
+ String? name,
+ String? iconName,
+ int? sortOrder,
+ int? createdAt,
+ }) => RoomsData(
+ id: id ?? this.id,
+ name: name ?? this.name,
+ iconName: iconName ?? this.iconName,
+ sortOrder: sortOrder ?? this.sortOrder,
+ createdAt: createdAt ?? this.createdAt,
+ );
+ RoomsData copyWithCompanion(RoomsCompanion data) {
+ return RoomsData(
+ id: data.id.present ? data.id.value : this.id,
+ name: data.name.present ? data.name.value : this.name,
+ iconName: data.iconName.present ? data.iconName.value : this.iconName,
+ sortOrder: data.sortOrder.present ? data.sortOrder.value : this.sortOrder,
+ createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt,
+ );
+ }
+
+ @override
+ String toString() {
+ return (StringBuffer('RoomsData(')
+ ..write('id: $id, ')
+ ..write('name: $name, ')
+ ..write('iconName: $iconName, ')
+ ..write('sortOrder: $sortOrder, ')
+ ..write('createdAt: $createdAt')
+ ..write(')'))
+ .toString();
+ }
+
+ @override
+ int get hashCode => Object.hash(id, name, iconName, sortOrder, createdAt);
+ @override
+ bool operator ==(Object other) =>
+ identical(this, other) ||
+ (other is RoomsData &&
+ other.id == this.id &&
+ other.name == this.name &&
+ other.iconName == this.iconName &&
+ other.sortOrder == this.sortOrder &&
+ other.createdAt == this.createdAt);
+}
+
+class RoomsCompanion extends UpdateCompanion {
+ final Value id;
+ final Value name;
+ final Value iconName;
+ final Value sortOrder;
+ final Value createdAt;
+ const RoomsCompanion({
+ this.id = const Value.absent(),
+ this.name = const Value.absent(),
+ this.iconName = const Value.absent(),
+ this.sortOrder = const Value.absent(),
+ this.createdAt = const Value.absent(),
+ });
+ RoomsCompanion.insert({
+ this.id = const Value.absent(),
+ required String name,
+ required String iconName,
+ this.sortOrder = const Value.absent(),
+ required int createdAt,
+ }) : name = Value(name),
+ iconName = Value(iconName),
+ createdAt = Value(createdAt);
+ static Insertable custom({
+ Expression? id,
+ Expression? name,
+ Expression? iconName,
+ Expression? sortOrder,
+ Expression? createdAt,
+ }) {
+ return RawValuesInsertable({
+ if (id != null) 'id': id,
+ if (name != null) 'name': name,
+ if (iconName != null) 'icon_name': iconName,
+ if (sortOrder != null) 'sort_order': sortOrder,
+ if (createdAt != null) 'created_at': createdAt,
+ });
+ }
+
+ RoomsCompanion copyWith({
+ Value? id,
+ Value? name,
+ Value? iconName,
+ Value? sortOrder,
+ Value? createdAt,
+ }) {
+ return RoomsCompanion(
+ id: id ?? this.id,
+ name: name ?? this.name,
+ iconName: iconName ?? this.iconName,
+ sortOrder: sortOrder ?? this.sortOrder,
+ createdAt: createdAt ?? this.createdAt,
+ );
+ }
+
+ @override
+ Map toColumns(bool nullToAbsent) {
+ final map = {};
+ if (id.present) {
+ map['id'] = Variable(id.value);
+ }
+ if (name.present) {
+ map['name'] = Variable(name.value);
+ }
+ if (iconName.present) {
+ map['icon_name'] = Variable(iconName.value);
+ }
+ if (sortOrder.present) {
+ map['sort_order'] = Variable(sortOrder.value);
+ }
+ if (createdAt.present) {
+ map['created_at'] = Variable(createdAt.value);
+ }
+ return map;
+ }
+
+ @override
+ String toString() {
+ return (StringBuffer('RoomsCompanion(')
+ ..write('id: $id, ')
+ ..write('name: $name, ')
+ ..write('iconName: $iconName, ')
+ ..write('sortOrder: $sortOrder, ')
+ ..write('createdAt: $createdAt')
+ ..write(')'))
+ .toString();
+ }
+}
+
+class Tasks extends Table with TableInfo {
+ @override
+ final GeneratedDatabase attachedDatabase;
+ final String? _alias;
+ Tasks(this.attachedDatabase, [this._alias]);
+ late final GeneratedColumn id = GeneratedColumn(
+ 'id',
+ aliasedName,
+ false,
+ hasAutoIncrement: true,
+ type: DriftSqlType.int,
+ requiredDuringInsert: false,
+ $customConstraints: 'NOT NULL PRIMARY KEY AUTOINCREMENT',
+ );
+ late final GeneratedColumn roomId = GeneratedColumn(
+ 'room_id',
+ aliasedName,
+ false,
+ type: DriftSqlType.int,
+ requiredDuringInsert: true,
+ $customConstraints: 'NOT NULL REFERENCES rooms(id)',
+ );
+ late final GeneratedColumn name = GeneratedColumn(
+ 'name',
+ aliasedName,
+ false,
+ type: DriftSqlType.string,
+ requiredDuringInsert: true,
+ $customConstraints: 'NOT NULL',
+ );
+ late final GeneratedColumn description = GeneratedColumn(
+ 'description',
+ aliasedName,
+ true,
+ type: DriftSqlType.string,
+ requiredDuringInsert: false,
+ $customConstraints: 'NULL',
+ );
+ late final GeneratedColumn intervalType = GeneratedColumn(
+ 'interval_type',
+ aliasedName,
+ false,
+ type: DriftSqlType.int,
+ requiredDuringInsert: true,
+ $customConstraints: 'NOT NULL',
+ );
+ late final GeneratedColumn intervalDays = GeneratedColumn(
+ 'interval_days',
+ aliasedName,
+ false,
+ type: DriftSqlType.int,
+ requiredDuringInsert: false,
+ $customConstraints: 'NOT NULL DEFAULT 1',
+ defaultValue: const CustomExpression('1'),
+ );
+ late final GeneratedColumn anchorDay = GeneratedColumn(
+ 'anchor_day',
+ aliasedName,
+ true,
+ type: DriftSqlType.int,
+ requiredDuringInsert: false,
+ $customConstraints: 'NULL',
+ );
+ late final GeneratedColumn effortLevel = GeneratedColumn(
+ 'effort_level',
+ aliasedName,
+ false,
+ type: DriftSqlType.int,
+ requiredDuringInsert: true,
+ $customConstraints: 'NOT NULL',
+ );
+ late final GeneratedColumn nextDueDate = GeneratedColumn(
+ 'next_due_date',
+ aliasedName,
+ false,
+ type: DriftSqlType.int,
+ requiredDuringInsert: true,
+ $customConstraints: 'NOT NULL',
+ );
+ late final GeneratedColumn createdAt = GeneratedColumn(
+ 'created_at',
+ aliasedName,
+ false,
+ type: DriftSqlType.int,
+ requiredDuringInsert: true,
+ $customConstraints: 'NOT NULL',
+ );
+ @override
+ List get $columns => [
+ id,
+ roomId,
+ name,
+ description,
+ intervalType,
+ intervalDays,
+ anchorDay,
+ effortLevel,
+ nextDueDate,
+ createdAt,
+ ];
+ @override
+ String get aliasedName => _alias ?? actualTableName;
+ @override
+ String get actualTableName => $name;
+ static const String $name = 'tasks';
+ @override
+ Set get $primaryKey => {id};
+ @override
+ TasksData map(Map data, {String? tablePrefix}) {
+ final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
+ return TasksData(
+ id: attachedDatabase.typeMapping.read(
+ DriftSqlType.int,
+ data['${effectivePrefix}id'],
+ )!,
+ roomId: attachedDatabase.typeMapping.read(
+ DriftSqlType.int,
+ data['${effectivePrefix}room_id'],
+ )!,
+ name: attachedDatabase.typeMapping.read(
+ DriftSqlType.string,
+ data['${effectivePrefix}name'],
+ )!,
+ description: attachedDatabase.typeMapping.read(
+ DriftSqlType.string,
+ data['${effectivePrefix}description'],
+ ),
+ intervalType: attachedDatabase.typeMapping.read(
+ DriftSqlType.int,
+ data['${effectivePrefix}interval_type'],
+ )!,
+ intervalDays: attachedDatabase.typeMapping.read(
+ DriftSqlType.int,
+ data['${effectivePrefix}interval_days'],
+ )!,
+ anchorDay: attachedDatabase.typeMapping.read(
+ DriftSqlType.int,
+ data['${effectivePrefix}anchor_day'],
+ ),
+ effortLevel: attachedDatabase.typeMapping.read(
+ DriftSqlType.int,
+ data['${effectivePrefix}effort_level'],
+ )!,
+ nextDueDate: attachedDatabase.typeMapping.read(
+ DriftSqlType.int,
+ data['${effectivePrefix}next_due_date'],
+ )!,
+ createdAt: attachedDatabase.typeMapping.read(
+ DriftSqlType.int,
+ data['${effectivePrefix}created_at'],
+ )!,
+ );
+ }
+
+ @override
+ Tasks createAlias(String alias) {
+ return Tasks(attachedDatabase, alias);
+ }
+
+ @override
+ bool get dontWriteConstraints => true;
+}
+
+class TasksData extends DataClass implements Insertable {
+ final int id;
+ final int roomId;
+ final String name;
+ final String? description;
+ final int intervalType;
+ final int intervalDays;
+ final int? anchorDay;
+ final int effortLevel;
+ final int nextDueDate;
+ final int createdAt;
+ const TasksData({
+ required this.id,
+ required this.roomId,
+ required this.name,
+ this.description,
+ required this.intervalType,
+ required this.intervalDays,
+ this.anchorDay,
+ required this.effortLevel,
+ required this.nextDueDate,
+ required this.createdAt,
+ });
+ @override
+ Map toColumns(bool nullToAbsent) {
+ final map = {};
+ map['id'] = Variable(id);
+ map['room_id'] = Variable(roomId);
+ map['name'] = Variable(name);
+ if (!nullToAbsent || description != null) {
+ map['description'] = Variable(description);
+ }
+ map['interval_type'] = Variable(intervalType);
+ map['interval_days'] = Variable(intervalDays);
+ if (!nullToAbsent || anchorDay != null) {
+ map['anchor_day'] = Variable(anchorDay);
+ }
+ map['effort_level'] = Variable(effortLevel);
+ map['next_due_date'] = Variable(nextDueDate);
+ map['created_at'] = Variable(createdAt);
+ return map;
+ }
+
+ TasksCompanion toCompanion(bool nullToAbsent) {
+ return TasksCompanion(
+ id: Value(id),
+ roomId: Value(roomId),
+ name: Value(name),
+ description: description == null && nullToAbsent
+ ? const Value.absent()
+ : Value(description),
+ intervalType: Value(intervalType),
+ intervalDays: Value(intervalDays),
+ anchorDay: anchorDay == null && nullToAbsent
+ ? const Value.absent()
+ : Value(anchorDay),
+ effortLevel: Value(effortLevel),
+ nextDueDate: Value(nextDueDate),
+ createdAt: Value(createdAt),
+ );
+ }
+
+ factory TasksData.fromJson(
+ Map json, {
+ ValueSerializer? serializer,
+ }) {
+ serializer ??= driftRuntimeOptions.defaultSerializer;
+ return TasksData(
+ id: serializer.fromJson(json['id']),
+ roomId: serializer.fromJson(json['roomId']),
+ name: serializer.fromJson(json['name']),
+ description: serializer.fromJson(json['description']),
+ intervalType: serializer.fromJson(json['intervalType']),
+ intervalDays: serializer.fromJson(json['intervalDays']),
+ anchorDay: serializer.fromJson(json['anchorDay']),
+ effortLevel: serializer.fromJson(json['effortLevel']),
+ nextDueDate: serializer.fromJson(json['nextDueDate']),
+ createdAt: serializer.fromJson(json['createdAt']),
+ );
+ }
+ @override
+ Map toJson({ValueSerializer? serializer}) {
+ serializer ??= driftRuntimeOptions.defaultSerializer;
+ return {
+ 'id': serializer.toJson(id),
+ 'roomId': serializer.toJson(roomId),
+ 'name': serializer.toJson(name),
+ 'description': serializer.toJson(description),
+ 'intervalType': serializer.toJson(intervalType),
+ 'intervalDays': serializer.toJson(intervalDays),
+ 'anchorDay': serializer.toJson(anchorDay),
+ 'effortLevel': serializer.toJson(effortLevel),
+ 'nextDueDate': serializer.toJson(nextDueDate),
+ 'createdAt': serializer.toJson(createdAt),
+ };
+ }
+
+ TasksData copyWith({
+ int? id,
+ int? roomId,
+ String? name,
+ Value description = const Value.absent(),
+ int? intervalType,
+ int? intervalDays,
+ Value anchorDay = const Value.absent(),
+ int? effortLevel,
+ int? nextDueDate,
+ int? createdAt,
+ }) => TasksData(
+ id: id ?? this.id,
+ roomId: roomId ?? this.roomId,
+ name: name ?? this.name,
+ description: description.present ? description.value : this.description,
+ intervalType: intervalType ?? this.intervalType,
+ intervalDays: intervalDays ?? this.intervalDays,
+ anchorDay: anchorDay.present ? anchorDay.value : this.anchorDay,
+ effortLevel: effortLevel ?? this.effortLevel,
+ nextDueDate: nextDueDate ?? this.nextDueDate,
+ createdAt: createdAt ?? this.createdAt,
+ );
+ TasksData copyWithCompanion(TasksCompanion data) {
+ return TasksData(
+ id: data.id.present ? data.id.value : this.id,
+ roomId: data.roomId.present ? data.roomId.value : this.roomId,
+ name: data.name.present ? data.name.value : this.name,
+ description: data.description.present
+ ? data.description.value
+ : this.description,
+ intervalType: data.intervalType.present
+ ? data.intervalType.value
+ : this.intervalType,
+ intervalDays: data.intervalDays.present
+ ? data.intervalDays.value
+ : this.intervalDays,
+ anchorDay: data.anchorDay.present ? data.anchorDay.value : this.anchorDay,
+ effortLevel: data.effortLevel.present
+ ? data.effortLevel.value
+ : this.effortLevel,
+ nextDueDate: data.nextDueDate.present
+ ? data.nextDueDate.value
+ : this.nextDueDate,
+ createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt,
+ );
+ }
+
+ @override
+ String toString() {
+ return (StringBuffer('TasksData(')
+ ..write('id: $id, ')
+ ..write('roomId: $roomId, ')
+ ..write('name: $name, ')
+ ..write('description: $description, ')
+ ..write('intervalType: $intervalType, ')
+ ..write('intervalDays: $intervalDays, ')
+ ..write('anchorDay: $anchorDay, ')
+ ..write('effortLevel: $effortLevel, ')
+ ..write('nextDueDate: $nextDueDate, ')
+ ..write('createdAt: $createdAt')
+ ..write(')'))
+ .toString();
+ }
+
+ @override
+ int get hashCode => Object.hash(
+ id,
+ roomId,
+ name,
+ description,
+ intervalType,
+ intervalDays,
+ anchorDay,
+ effortLevel,
+ nextDueDate,
+ createdAt,
+ );
+ @override
+ bool operator ==(Object other) =>
+ identical(this, other) ||
+ (other is TasksData &&
+ other.id == this.id &&
+ other.roomId == this.roomId &&
+ other.name == this.name &&
+ other.description == this.description &&
+ other.intervalType == this.intervalType &&
+ other.intervalDays == this.intervalDays &&
+ other.anchorDay == this.anchorDay &&
+ other.effortLevel == this.effortLevel &&
+ other.nextDueDate == this.nextDueDate &&
+ other.createdAt == this.createdAt);
+}
+
+class TasksCompanion extends UpdateCompanion {
+ final Value id;
+ final Value roomId;
+ final Value name;
+ final Value description;
+ final Value intervalType;
+ final Value intervalDays;
+ final Value anchorDay;
+ final Value effortLevel;
+ final Value nextDueDate;
+ final Value createdAt;
+ const TasksCompanion({
+ this.id = const Value.absent(),
+ this.roomId = const Value.absent(),
+ this.name = const Value.absent(),
+ this.description = const Value.absent(),
+ this.intervalType = const Value.absent(),
+ this.intervalDays = const Value.absent(),
+ this.anchorDay = const Value.absent(),
+ this.effortLevel = const Value.absent(),
+ this.nextDueDate = const Value.absent(),
+ this.createdAt = const Value.absent(),
+ });
+ TasksCompanion.insert({
+ this.id = const Value.absent(),
+ required int roomId,
+ required String name,
+ this.description = const Value.absent(),
+ required int intervalType,
+ this.intervalDays = const Value.absent(),
+ this.anchorDay = const Value.absent(),
+ required int effortLevel,
+ required int nextDueDate,
+ required int createdAt,
+ }) : roomId = Value(roomId),
+ name = Value(name),
+ intervalType = Value(intervalType),
+ effortLevel = Value(effortLevel),
+ nextDueDate = Value(nextDueDate),
+ createdAt = Value(createdAt);
+ static Insertable custom({
+ Expression? id,
+ Expression? roomId,
+ Expression? name,
+ Expression? description,
+ Expression? intervalType,
+ Expression? intervalDays,
+ Expression? anchorDay,
+ Expression? effortLevel,
+ Expression? nextDueDate,
+ Expression? createdAt,
+ }) {
+ return RawValuesInsertable({
+ if (id != null) 'id': id,
+ if (roomId != null) 'room_id': roomId,
+ if (name != null) 'name': name,
+ if (description != null) 'description': description,
+ if (intervalType != null) 'interval_type': intervalType,
+ if (intervalDays != null) 'interval_days': intervalDays,
+ if (anchorDay != null) 'anchor_day': anchorDay,
+ if (effortLevel != null) 'effort_level': effortLevel,
+ if (nextDueDate != null) 'next_due_date': nextDueDate,
+ if (createdAt != null) 'created_at': createdAt,
+ });
+ }
+
+ TasksCompanion copyWith({
+ Value? id,
+ Value? roomId,
+ Value? name,
+ Value? description,
+ Value? intervalType,
+ Value? intervalDays,
+ Value? anchorDay,
+ Value? effortLevel,
+ Value? nextDueDate,
+ Value? createdAt,
+ }) {
+ return TasksCompanion(
+ id: id ?? this.id,
+ roomId: roomId ?? this.roomId,
+ name: name ?? this.name,
+ description: description ?? this.description,
+ intervalType: intervalType ?? this.intervalType,
+ intervalDays: intervalDays ?? this.intervalDays,
+ anchorDay: anchorDay ?? this.anchorDay,
+ effortLevel: effortLevel ?? this.effortLevel,
+ nextDueDate: nextDueDate ?? this.nextDueDate,
+ createdAt: createdAt ?? this.createdAt,
+ );
+ }
+
+ @override
+ Map toColumns(bool nullToAbsent) {
+ final map = {};
+ if (id.present) {
+ map['id'] = Variable(id.value);
+ }
+ if (roomId.present) {
+ map['room_id'] = Variable(roomId.value);
+ }
+ if (name.present) {
+ map['name'] = Variable(name.value);
+ }
+ if (description.present) {
+ map['description'] = Variable(description.value);
+ }
+ if (intervalType.present) {
+ map['interval_type'] = Variable(intervalType.value);
+ }
+ if (intervalDays.present) {
+ map['interval_days'] = Variable(intervalDays.value);
+ }
+ if (anchorDay.present) {
+ map['anchor_day'] = Variable(anchorDay.value);
+ }
+ if (effortLevel.present) {
+ map['effort_level'] = Variable(effortLevel.value);
+ }
+ if (nextDueDate.present) {
+ map['next_due_date'] = Variable(nextDueDate.value);
+ }
+ if (createdAt.present) {
+ map['created_at'] = Variable(createdAt.value);
+ }
+ return map;
+ }
+
+ @override
+ String toString() {
+ return (StringBuffer('TasksCompanion(')
+ ..write('id: $id, ')
+ ..write('roomId: $roomId, ')
+ ..write('name: $name, ')
+ ..write('description: $description, ')
+ ..write('intervalType: $intervalType, ')
+ ..write('intervalDays: $intervalDays, ')
+ ..write('anchorDay: $anchorDay, ')
+ ..write('effortLevel: $effortLevel, ')
+ ..write('nextDueDate: $nextDueDate, ')
+ ..write('createdAt: $createdAt')
+ ..write(')'))
+ .toString();
+ }
+}
+
+class TaskCompletions extends Table
+ with TableInfo {
+ @override
+ final GeneratedDatabase attachedDatabase;
+ final String? _alias;
+ TaskCompletions(this.attachedDatabase, [this._alias]);
+ late final GeneratedColumn id = GeneratedColumn(
+ 'id',
+ aliasedName,
+ false,
+ hasAutoIncrement: true,
+ type: DriftSqlType.int,
+ requiredDuringInsert: false,
+ $customConstraints: 'NOT NULL PRIMARY KEY AUTOINCREMENT',
+ );
+ late final GeneratedColumn taskId = GeneratedColumn(
+ 'task_id',
+ aliasedName,
+ false,
+ type: DriftSqlType.int,
+ requiredDuringInsert: true,
+ $customConstraints: 'NOT NULL REFERENCES tasks(id)',
+ );
+ late final GeneratedColumn completedAt = GeneratedColumn(
+ 'completed_at',
+ aliasedName,
+ false,
+ type: DriftSqlType.int,
+ requiredDuringInsert: true,
+ $customConstraints: 'NOT NULL',
+ );
+ @override
+ List get $columns => [id, taskId, completedAt];
+ @override
+ String get aliasedName => _alias ?? actualTableName;
+ @override
+ String get actualTableName => $name;
+ static const String $name = 'task_completions';
+ @override
+ Set get $primaryKey => {id};
+ @override
+ TaskCompletionsData map(Map data, {String? tablePrefix}) {
+ final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
+ return TaskCompletionsData(
+ id: attachedDatabase.typeMapping.read(
+ DriftSqlType.int,
+ data['${effectivePrefix}id'],
+ )!,
+ taskId: attachedDatabase.typeMapping.read(
+ DriftSqlType.int,
+ data['${effectivePrefix}task_id'],
+ )!,
+ completedAt: attachedDatabase.typeMapping.read(
+ DriftSqlType.int,
+ data['${effectivePrefix}completed_at'],
+ )!,
+ );
+ }
+
+ @override
+ TaskCompletions createAlias(String alias) {
+ return TaskCompletions(attachedDatabase, alias);
+ }
+
+ @override
+ bool get dontWriteConstraints => true;
+}
+
+class TaskCompletionsData extends DataClass
+ implements Insertable {
+ final int id;
+ final int taskId;
+ final int completedAt;
+ const TaskCompletionsData({
+ required this.id,
+ required this.taskId,
+ required this.completedAt,
+ });
+ @override
+ Map toColumns(bool nullToAbsent) {
+ final map = {};
+ map['id'] = Variable(id);
+ map['task_id'] = Variable(taskId);
+ map['completed_at'] = Variable(completedAt);
+ return map;
+ }
+
+ TaskCompletionsCompanion toCompanion(bool nullToAbsent) {
+ return TaskCompletionsCompanion(
+ id: Value(id),
+ taskId: Value(taskId),
+ completedAt: Value(completedAt),
+ );
+ }
+
+ factory TaskCompletionsData.fromJson(
+ Map json, {
+ ValueSerializer? serializer,
+ }) {
+ serializer ??= driftRuntimeOptions.defaultSerializer;
+ return TaskCompletionsData(
+ id: serializer.fromJson(json['id']),
+ taskId: serializer.fromJson(json['taskId']),
+ completedAt: serializer.fromJson(json['completedAt']),
+ );
+ }
+ @override
+ Map toJson({ValueSerializer? serializer}) {
+ serializer ??= driftRuntimeOptions.defaultSerializer;
+ return {
+ 'id': serializer.toJson(id),
+ 'taskId': serializer.toJson(taskId),
+ 'completedAt': serializer.toJson(completedAt),
+ };
+ }
+
+ TaskCompletionsData copyWith({int? id, int? taskId, int? completedAt}) =>
+ TaskCompletionsData(
+ id: id ?? this.id,
+ taskId: taskId ?? this.taskId,
+ completedAt: completedAt ?? this.completedAt,
+ );
+ TaskCompletionsData copyWithCompanion(TaskCompletionsCompanion data) {
+ return TaskCompletionsData(
+ id: data.id.present ? data.id.value : this.id,
+ taskId: data.taskId.present ? data.taskId.value : this.taskId,
+ completedAt: data.completedAt.present
+ ? data.completedAt.value
+ : this.completedAt,
+ );
+ }
+
+ @override
+ String toString() {
+ return (StringBuffer('TaskCompletionsData(')
+ ..write('id: $id, ')
+ ..write('taskId: $taskId, ')
+ ..write('completedAt: $completedAt')
+ ..write(')'))
+ .toString();
+ }
+
+ @override
+ int get hashCode => Object.hash(id, taskId, completedAt);
+ @override
+ bool operator ==(Object other) =>
+ identical(this, other) ||
+ (other is TaskCompletionsData &&
+ other.id == this.id &&
+ other.taskId == this.taskId &&
+ other.completedAt == this.completedAt);
+}
+
+class TaskCompletionsCompanion extends UpdateCompanion {
+ final Value id;
+ final Value taskId;
+ final Value completedAt;
+ const TaskCompletionsCompanion({
+ this.id = const Value.absent(),
+ this.taskId = const Value.absent(),
+ this.completedAt = const Value.absent(),
+ });
+ TaskCompletionsCompanion.insert({
+ this.id = const Value.absent(),
+ required int taskId,
+ required int completedAt,
+ }) : taskId = Value(taskId),
+ completedAt = Value(completedAt);
+ static Insertable custom({
+ Expression? id,
+ Expression? taskId,
+ Expression? completedAt,
+ }) {
+ return RawValuesInsertable({
+ if (id != null) 'id': id,
+ if (taskId != null) 'task_id': taskId,
+ if (completedAt != null) 'completed_at': completedAt,
+ });
+ }
+
+ TaskCompletionsCompanion copyWith({
+ Value? id,
+ Value? taskId,
+ Value? completedAt,
+ }) {
+ return TaskCompletionsCompanion(
+ id: id ?? this.id,
+ taskId: taskId ?? this.taskId,
+ completedAt: completedAt ?? this.completedAt,
+ );
+ }
+
+ @override
+ Map toColumns(bool nullToAbsent) {
+ final map = {};
+ if (id.present) {
+ map['id'] = Variable(id.value);
+ }
+ if (taskId.present) {
+ map['task_id'] = Variable(taskId.value);
+ }
+ if (completedAt.present) {
+ map['completed_at'] = Variable(completedAt.value);
+ }
+ return map;
+ }
+
+ @override
+ String toString() {
+ return (StringBuffer('TaskCompletionsCompanion(')
+ ..write('id: $id, ')
+ ..write('taskId: $taskId, ')
+ ..write('completedAt: $completedAt')
+ ..write(')'))
+ .toString();
+ }
+}
+
+class DatabaseAtV2 extends GeneratedDatabase {
+ DatabaseAtV2(QueryExecutor e) : super(e);
+ late final Rooms rooms = Rooms(this);
+ late final Tasks tasks = Tasks(this);
+ late final TaskCompletions taskCompletions = TaskCompletions(this);
+ @override
+ Iterable> get allTables =>
+ allSchemaEntities.whereType>();
+ @override
+ List get allSchemaEntities => [
+ rooms,
+ tasks,
+ taskCompletions,
+ ];
+ @override
+ int get schemaVersion => 2;
+}