FilterGroup / FilterLeaf tree model (lib/core/filter/filter_expression.dart) — sealed hierarchy with FilterField (from, to, cc, subject, size), FilterComparison (contains, is, matches, over, under), and FilterOperator (AND / OR).
SieveSerializer (lib/core/sieve/sieve_serializer.dart) — converts a FilterGroup + List<SieveAction> to a valid RFC 5228 Sieve script.
FilterSieveConverter (lib/core/filter/filter_sieve_converter.dart) — parses a Sieve script back into a FilterGroup tree; returns null for unsupported scripts.
FilterBuilderWidget (lib/ui/widgets/filter_builder.dart) — interactive filter editor with AND/OR toggle, nested group support (depth ≤ 1).
Search screen gains an Advanced Search mode (Icons.tune toggle).
Closes #466
## Summary
- **`FilterGroup` / `FilterLeaf` tree model** (`lib/core/filter/filter_expression.dart`) — sealed hierarchy with `FilterField` (from, to, cc, subject, size), `FilterComparison` (contains, is, matches, over, under), and `FilterOperator` (AND / OR).
- **`SieveSerializer`** (`lib/core/sieve/sieve_serializer.dart`) — converts a `FilterGroup` + `List<SieveAction>` to a valid RFC 5228 Sieve script.
- **`FilterSieveConverter`** (`lib/core/filter/filter_sieve_converter.dart`) — parses a Sieve script back into a `FilterGroup` tree; returns `null` for unsupported scripts.
- **`FilterBuilderWidget`** (`lib/ui/widgets/filter_builder.dart`) — interactive filter editor with AND/OR toggle, nested group support (depth ≤ 1).
- **Search screen** gains an Advanced Search mode (`Icons.tune` toggle).
- **Sieve script editor** gains Visual / Script tabs with round-trip serialization. `_ActionEditor` covers keep, discard, mark-as-read, file-into.
- **25 unit tests** covering all new model/logic classes including round-trip.
- Fix: `SieveSerializer` now emits `\\Seen` so the IMAP flag survives quoted-string parsing.
## Test plan
- [x] `flutter analyze` — No issues found
- [x] `flutter test test/unit/filter_and_sieve_test.dart` — all 25 tests pass
- [x] All pre-commit hooks pass (format, check-fast, coverage gate)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Closes #466
Summary
FilterGroup/FilterLeaftree model (lib/core/filter/filter_expression.dart) — sealed hierarchy withFilterField(from, to, cc, subject, size),FilterComparison(contains, is, matches, over, under), andFilterOperator(AND / OR).SieveSerializer(lib/core/sieve/sieve_serializer.dart) — converts aFilterGroup+List<SieveAction>to a valid RFC 5228 Sieve script.FilterSieveConverter(lib/core/filter/filter_sieve_converter.dart) — parses a Sieve script back into aFilterGrouptree; returnsnullfor unsupported scripts.FilterBuilderWidget(lib/ui/widgets/filter_builder.dart) — interactive filter editor with AND/OR toggle, nested group support (depth ≤ 1).Icons.tunetoggle)._ActionEditorcovers keep, discard, mark-as-read, file-into.SieveSerializernow emits\\Seenso the IMAP flag survives quoted-string parsing.Test plan
flutter analyze— No issues foundflutter test test/unit/filter_and_sieve_test.dart— all 25 tests pass🤖 Generated with Claude Code