feat(todo): filters in Todoist's language, and a view of each label (ADR 0033, D35)

A filter is a query read on the device, as the server sees no task, kept
sealed in `saved_filter`. Filters & labels is a screen of its own under
Browse; a label opens its tasks, and favourite filters and labels join
Browse's Favourites. D36 records what of Todoist's Pro stays out.

Whats-New: Filters: keep views like "today & p1", and open a label to see its tasks, under Browse in Filters & labels.
Whats-New-De: Filter: Speichere Ansichten wie „heute & p1“ und öffne ein Label, um seine Aufgaben zu sehen, in der Übersicht unter Filter & Labels.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
Tizian 「ティツィアーン」 2026-11-06 19:44:46 +01:00
commit b1f2078357
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64

View file

@ -23,6 +23,7 @@ import 'package:serverpod_client/serverpod_client.dart' as _isc;
import 'package:serverpod_database/serverpod_database.dart' as _isd;
import 'package:serverpod_offline_sync_client/serverpod_offline_sync_client.dart'
as _ipulbpi2;
import 'filter/saved_filter.dart' as _i9q9fhid;
import 'label/label.dart' as _ivak08z4;
import 'privacy/content_key.dart' as _imed3x5d;
import 'project/project.dart' as _i9c44spp;
@ -33,6 +34,7 @@ import 'search/place_point.dart' as _itf0ur2u;
import 'search/search_refused.dart' as _ihbxkwke;
import 'settings/todo_settings.dart' as _icak60vd;
import 'task/task.dart' as _ib4f8uyw;
export 'filter/saved_filter.dart';
export 'label/label.dart';
export 'privacy/content_key.dart';
export 'project/project.dart';
@ -249,6 +251,73 @@ class Protocol extends _isd.DatabaseSerializationManager {
],
managed: true,
),
_isd.TableDefinition(
name: 'saved_filter',
dartName: 'SavedFilter',
schema: 'public',
module: 'halkyon_todo',
columns: [
_isd.ColumnDefinition(
name: 'id',
columnType: _isd.ColumnType.uuid,
isNullable: false,
dartType: 'UuidValue?',
columnDefault: 'random_v7',
),
_isd.ColumnDefinition(
name: 'spaceId',
columnType: _isd.ColumnType.bigint,
isNullable: true,
dartType: 'int?',
),
_isd.ColumnDefinition(
name: 'keyId',
columnType: _isd.ColumnType.text,
isNullable: true,
dartType: 'String?',
),
_isd.ColumnDefinition(
name: 'payload',
columnType: _isd.ColumnType.bytea,
isNullable: false,
dartType: 'dart:typed_data:ByteData',
),
_isd.ColumnDefinition(
name: 'nonce',
columnType: _isd.ColumnType.bytea,
isNullable: true,
dartType: 'dart:typed_data:ByteData?',
),
],
foreignKeys: [
_isd.ForeignKeyDefinition(
constraintName: 'saved_filter_fk_0',
columns: ['spaceId'],
referenceTable: 'offline_sync_spaces',
referenceTableSchema: 'public',
referenceColumns: ['id'],
onUpdate: _isd.ForeignKeyAction.noAction,
onDelete: _isd.ForeignKeyAction.cascade,
matchType: null,
),
],
indexes: [
_isd.IndexDefinition(
indexName: 'saved_filter_space_idx',
tableSpace: null,
elements: [
_isd.IndexElementDefinition(
type: _isd.IndexElementDefinitionType.column,
definition: 'spaceId',
),
],
type: 'btree',
isUnique: false,
isPrimary: false,
),
],
managed: true,
),
_isd.TableDefinition(
name: 'section',
dartName: 'Section',
@ -499,6 +568,9 @@ class Protocol extends _isd.DatabaseSerializationManager {
}
}
if (t == _i9q9fhid.SavedFilter) {
return _i9q9fhid.SavedFilter.fromJson(data) as T;
}
if (t == _ivak08z4.Label) {
return _ivak08z4.Label.fromJson(data) as T;
}
@ -529,6 +601,9 @@ class Protocol extends _isd.DatabaseSerializationManager {
if (t == _ib4f8uyw.Task) {
return _ib4f8uyw.Task.fromJson(data) as T;
}
if (t == _isc.getType<_i9q9fhid.SavedFilter?>()) {
return (data != null ? _i9q9fhid.SavedFilter.fromJson(data) : null) as T;
}
if (t == _isc.getType<_ivak08z4.Label?>()) {
return (data != null ? _ivak08z4.Label.fromJson(data) : null) as T;
}
@ -588,6 +663,7 @@ class Protocol extends _isd.DatabaseSerializationManager {
static String? getClassNameForType(Type type) {
return switch (type) {
_i9q9fhid.SavedFilter => 'SavedFilter',
_ivak08z4.Label => 'Label',
_imed3x5d.ContentKey => 'ContentKey',
_i9c44spp.Project => 'Project',
@ -615,6 +691,8 @@ class Protocol extends _isd.DatabaseSerializationManager {
}
switch (data) {
case _i9q9fhid.SavedFilter():
return 'SavedFilter';
case _ivak08z4.Label():
return 'Label';
case _imed3x5d.ContentKey():
@ -671,6 +749,9 @@ class Protocol extends _isd.DatabaseSerializationManager {
if (dataClassName is! String) {
return super.deserializeByClassName(data);
}
if (dataClassName == 'SavedFilter') {
return deserialize<_i9q9fhid.SavedFilter>(data['data']);
}
if (dataClassName == 'Label') {
return deserialize<_ivak08z4.Label>(data['data']);
}
@ -780,6 +861,8 @@ class Protocol extends _isd.DatabaseSerializationManager {
}
}
switch (t) {
case _i9q9fhid.SavedFilter:
return _i9q9fhid.SavedFilter.t;
case _ivak08z4.Label:
return _ivak08z4.Label.t;
case _imed3x5d.ContentKey: