feat(channels): inline sidebar drag-reorder & text-type switching#107
Conversation
Add a ReorderableListView channel sidebar for managers (long-press to drag channels/categories, move channels between categories, persisted via per-bucket position + parent_id PATCH), and a Type selector in the channel edit dialog for non-destructive text<->announcement conversions. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
… add tests - _persist(): add _pendingPersist + _schedulePersist() so rapid drags never run two concurrent async persist operations; the second persist restarts after the first finishes rather than racing it. - _recomputeParents(): take the moved _DragEntry as a parameter and only update that entry's parentId. The old all-items walk would silently reparent uncategorized channels when a category was dragged before them, sending destructive parent_id PATCHes to the API. - Extract parseChannelPosition / channelListSignature to lib/features/channels/utils/channel_sort.dart; _pos in both accord_home_channels.dart and accord_channel_reorder.dart now delegate there, removing the three-way duplication with accord_channels.dart's _asInt. - Add test/features/channels/channel_sort_test.dart covering int/num/ String/null position parsing and signature order-independence. - Trim multi-line doc comments on private classes to single lines per project convention (CLAUDE.md: "one short line max"). https://claude.ai/code/session_018BoRo7xUkKYJ9ffh8tQfes
Review findings & fixes — commit fbae138All findings below have been fixed and pushed to this branch. 🔴 Critical — Bug1. Race condition in
Fix: Added 2. The inline drag list places uncategorized channels before all categories in Fix: 🟡 Medium — Code quality / maintainability3. The position-parsing helper (handle int / num / String / null → 0) existed identically in Fix: Extracted to 🟢 Low — Test coverage4. No tests for the position-parsing / signature logic The Fix: Added 🟢 Low — Style5. Multi-line doc comments on private classes Three new private classes ( ℹ️ Not fixed — noted for awareness
Generated by Claude Code |
…oo (#142) * fix(channels): use ReorderableListView.onReorder; gate CI on stable too `accord_home_channels.dart` called `ReorderableListView.builder` with `onReorderItem:`, which isn't a parameter on Flutter's built-in widget — it requires `onReorder:`. This was a hard `flutter analyze` error on stable (missing_required_argument + undefined_named_parameter), breaking any build touching the file. Fixes #138. The two APIs differ in `newIndex` semantics: `onReorderItem` reported the target index in post-removal coordinates, while `onReorder` reports it pre-removal (the dragged slot is still counted). Renamed the argument and added the canonical `if (newIndex > oldIndex) newIndex -= 1;` so the existing reorder logic — which indexes into the post-removal list — stays correct and drag-down moves don't land one slot too low. Why it reached master: the error landed in #107 and CI was green, because the analyze gate only ran the pinned `beta` channel, which tolerated `onReorderItem`. Matrix the analyze/test job over `[beta, stable]` so a widget/SDK API that diverges between channels fails the gate instead of shipping. Cache keys now include the channel so the legs don't collide. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * review(#142): add reorder-index tests and clarify FLUTTER_CHANNEL comment - Add 7 unit tests in channel_sort_test.dart covering the canonical `if (newIndex > oldIndex) newIndex -= 1` adjustment that fixes #138: drag-down by one slot (no-op), drag-down multiple slots, drag-down to last position, drag-up variants, and a regression guard that documents the exact wrong result produced without the fix. - Clarify the FLUTTER_CHANNEL env var comment in ci.yml: the analyze job now uses matrix.channel (beta + stable), so the env var only controls the build job — the previous comment implied it still drove analyze. https://claude.ai/code/session_0171kkokchuut5V7nmtibzLc --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Summary
ReorderableListViewsidebar — long-press to drag channels and categories into a new order, or move a channel under a different category. Dragging a category carries its children as a contiguous block. Changes persist via per-bucketposition(plusparent_idwhen a channel crosses a category boundary) with optimistic PATCH and end-of-run reconciliation. Non-managers keep the plainListView.text↔announcementconversions (mirrors accordserver'sis_non_destructive_type_change). Voice/category/forum show no selector since no safe conversion exists.This is an inline alternative to PR #100's modal reorder dialog — reordering happens directly in the sidebar.
Test plan
parent_idupdates🤖 Generated with Claude Code