Skip to content

feat: add inline comment apis#1199

Open
LucasXu0 wants to merge 18 commits intoAppFlowy-IO:flutter/3_27_4from
LucasXu0:flutter/3_27_4
Open

feat: add inline comment apis#1199
LucasXu0 wants to merge 18 commits intoAppFlowy-IO:flutter/3_27_4from
LucasXu0:flutter/3_27_4

Conversation

@LucasXu0
Copy link
Copy Markdown
Collaborator

No description provided.

LucasXu0 added 18 commits March 27, 2026 16:03
- Add `commentIds` ('comment-ids') attribute key to AppFlowyRichTextKeys,
  intentionally excluded from supportSliced so new adjacent text does not
  inherit comment anchors
- Add InlineComment value object with id, content, authorName, createdAt,
  isResolved, metadata fields and copyWith / equality by id
- Add InlineCommentController (ChangeNotifier) that manages a comment list
  and exposes updateComments, updateComment, removeComment, findById,
  highlightColorFor, plus OnCommentAdded / OnCommentDeleted / OnCommentTapped
  callback typedefs
- Make commentIds a const field in AppFlowyRichTextKeys
- Make commentHighlightColorBuilder final in InlineCommentController
- Replace try/catch in findById with explicit for-loop returning null
- Remove redundant runtimeType check in InlineComment operator==
- InlineCommentService: subscribes to editorState.transactionStream and
  detects when a comment anchor is fully removed from the document delta,
  then calls onCommentDeleted + removeComment on the controller.
- scanAnchors(): traverses all document nodes, collecting the first
  occurrence of each comment-id in the delta as a CommentAnchor.
- InlineCommentServiceWidget: StatefulWidget that starts the service,
  chains a comment decorator into EditorStyle.textSpanDecorator, and
  provides InlineCommentController to the sub-tree via InlineCommentScope.
- Includes a placeholder applyCommentDecoration function (Task 3 will
  replace it with the real highlight implementation).
- Replace placeholder `applyCommentDecoration` in inline_comment_service_widget.dart with import of real implementation
- Add comment_text_span_decorator.dart: highlights commented text with background color, underline, and tap gesture
- Add comment_card_widget.dart: animated card showing author, time, content, and delete action
- Add comment_sidebar_widget.dart: desktop sidebar that aligns comment cards to their text anchors
- [C-1] Fix TapGestureRecognizer memory leak: move recognizer lifecycle
  into _InlineCommentServiceWidgetState via a managed pool (_recognizers
  map); recognizers are disposed on controller change and widget teardown.
- [m-5] Eliminate second InlineCommentService instance in sidebar: extract
  scanDocumentAnchors() as a static method and call it directly from
  _CommentSidebarWidgetState, removing the extra transactionStream listener.
- [I-1] Remove duplicate _updateCommentPositions() scheduling from
  _buildSidebar's ListenableBuilder builder; the addListener path handles it.
- [I-2] Add didUpdateWidget to _CommentSidebarWidgetState to correctly
  re-subscribe when the controller prop changes.
- [I-3] Replace hardcoded Chinese string '删除' with English 'Delete'.
- [m-1] Replace unsafe rawIds.cast<String>() with rawIds.map((e) =>
  e.toString()).toList() to avoid runtime cast errors.
Implements desktop (ToolbarItem) and mobile (MobileToolbarItem) toolbar
buttons that add inline comment anchors to the selected text range by
calling InlineCommentController.onCommentAdded and writing the resulting
comment-id list into the delta via EditorState.formatDelta.
- [I-1] Add isSingle check to _isActive (desktop) and itemIconBuilder (mobile)
  so the toolbar button is disabled for multi-node selections, aligning
  with the handler's own guard.
- [I-2] Fix _collectExistingCommentIds to scan only the delta ops that overlap
  the selected range, avoiding false inclusion of comment-ids outside the selection.
- [M-1] Extract shared collectExistingCommentIds to comment_utils.dart,
  removing the duplicated private implementations in both toolbar files.
- [I-4] Wrap unawaited _addComment Future in mobile actionHandler with
  dart:async unawaited() to silence the lint warning.
- Add inlineCommentController, showCommentSidebar, sidebarWidth params to AppFlowyEditor
- Wire InlineCommentServiceWidget and CommentSidebarWidget in _buildServices()
- Export inline comment public API from appflowy_editor.dart
Replace the `commentToolbarItem` / `commentMobileToolbarItem` top-level
constants with factory functions `buildCommentToolbarItem(controller)` and
`buildCommentMobileToolbarItem(controller)` that receive an
`InlineCommentController` as a parameter instead of looking it up via
`InlineCommentScope.of(context)`.
…om AppFlowyEditor

Introduces InlineCommentWidget, a standalone wrapper that installs the
InlineCommentService and text-span decorator around any child widget,
so AppFlowyEditor no longer needs to know about comment functionality.
Also refactors CommentSidebarWidget to be a pure sidebar panel by
removing its child parameter and internal Row layout (now owned by
InlineCommentWidget).
Decouples inline comment support from the AppFlowyEditor widget by removing
inlineCommentController, showCommentSidebar, and sidebarWidth parameters,
their associated fields and assert, the InlineCommentServiceWidget usage in
_buildServices, and the now-unused inline_comment_service_widget.dart file.
Consumers should use the standalone InlineCommentWidget wrapper instead.
…integration tests

The InlineCommentWidget previously monkey-patched editorState.editorStyle.textSpanDecorator
in initState, but AppFlowyEditor._updateValues() unconditionally overwrites editorStyle in
both initState and didUpdateWidget, causing the decorator to be lost.

This commit introduces buildCommentTextSpanDecorator() as a public factory function that
callers pass via EditorStyle.textSpanDecorator, removing the runtime patching from
InlineCommentWidget entirely.
- Add avatar circle with author initial
- Subtle border for unfocused cards, tinted background for focused
- Left divider between sidebar and editor
- Softer delete button styling
- Toggle focus on tap (click again to unfocus)
- Compact relative time format
…ight

- Replace Stack+Positioned with SingleChildScrollView+Column to prevent
  card overlap regardless of content height
- Change Row crossAxisAlignment from start to stretch so sidebar fills
  full parent height
- Add proper padding (horizontal 12, vertical 16)
- Sort cards by document position (path + offset)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant