Social Components
Social components enable user interactions, content sharing, and community engagement in BookWish.
LineCard
A card displaying a user's "line" (post) about a book, with likes, replies, and sharing capabilities.
Usage
LineCard(
line: line,
isNested: false, // true for reply threads
)
Props
| Property | Type | Required | Default | Description |
|---|---|---|---|---|
line | Line | Yes | - | Line model with content, author, book reference |
isNested | bool | No | false | Whether line is a reply (affects styling) |
Anatomy
Header
- UserChip: Displays author avatar and name
- Timestamp: Relative time (via
timeAgo()utility)
Content
- Text: Line content with edit functionality for authors
- Edit Mode: TextField with Save/Cancel buttons when editing
- Character Limit: 1000 characters
Book Reference (parent lines only)
- BookMiniChip: Shows book thumbnail, title, and authors
- Tap: Opens BookInfoOverlay
Context Tags (parent lines only)
- Club badge: Shows "Book Club" with person icon
- Challenge badge: Shows "Challenge" with rosette icon
Actions
- Like Button: Heart icon with count, animated
- Reply Button: Chat bubble icon with count (parent lines only)
- Share Button: Share via share_plus package
- Menu: Report and Edit (for authors) options
Replies Section (parent lines only)
- Reply Input: TextField for authenticated users
- Reply List: Nested LineCards with
isNested: true - Character Limit: 500 characters for replies
States
- Normal: White background, elevation 2
- Nested: Parchment background, no elevation, 8px border radius
- Editing: Shows TextField with action buttons
- Submitting: Shows loading spinner on buttons
Features
- Inline Editing: Authors can edit their posts
- Threaded Replies: Expandable reply sections with nested cards
- Like Animation: Heart icon scales on tap
- Real-time Updates: Watches
lineRepliesNotifierProviderandfeedNotifierProvider - Auth-gated Actions: Reply input only shown for logged-in users
Styling
Parent Line
- Padding: 16px all
- Border radius: 12px
- Elevation: 2
Nested Reply
- Padding: 12px all
- Border radius: 8px
- Background:
AppColors.parchment - Left border: 2px ink blue at 0.2 alpha
ReviewCard
A card displaying a book review with star rating and like functionality.
Usage
ReviewCard(
review: review,
)
Props
| Property | Type | Required | Description |
|---|---|---|---|
review | Review | Yes | Review model with rating, content, book reference |
Anatomy
Header
- UserChip: Review author
- Rating Stars: 1-5 filled/outlined stars (18px, amber color)
Metadata
- Timestamp: Relative time display
Content
- Review Text: Optional text content in
AppTypography.cardBody - Max Lines: No limit (full text displayed)
Book Reference
- BookMiniChip: Same as LineCard
- Tap: Opens BookInfoOverlay
Actions
- Like Button: Shared component with count
- Menu: Report option
Rating Stars
The _RatingStars internal widget generates 5 stars:
- Filled:
CupertinoIcons.star_fillfor rating value - Outlined:
CupertinoIcons.starfor remaining - Color:
Colors.amber - Size: 18px
Styling
- Padding: 16px all
- Border radius: 12px
- Elevation: 2
- Background: White
Features
- Like Toggle: Via
reviewServiceProvider - Report: Opens ReportDialog
- Feed Integration: Refreshes
feedNotifierProvideron actions
UserChip
A compact user avatar and name display with tap-to-profile functionality.
Usage
UserChip(
user: user,
onTap: () => customAction(), // Optional override
)
Props
| Property | Type | Required | Description |
|---|---|---|---|
user | User | Yes | User model with avatar, displayName, username |
onTap | VoidCallback? | No | Custom tap handler (defaults to profile overlay) |
Anatomy
- Avatar: CircleAvatar with 16px radius
- With image:
NetworkImagefromuser.avatarUrl - Without image: Initial letter of name in
AppTypography.cardLabel
- With image:
- Name: Display name or username, 12px font size
- Weight: 600 font weight
Default Behavior
Tapping opens ProfileOverlay with user details unless custom onTap provided.
Styling
- Row layout with 8px gap
- Avatar radius: 16px (32px diameter)
- Text style:
AppTypography.cardLabelwith bold weight
UserAvatar
UserAvatar functionality is embedded in UserChip and NotificationTile.
Badge Types
While not explicitly a separate component, avatar badges appear in:
NotificationTile
- Type-specific background colors
- Icon overlays for notification types
- Falls back to actor's avatar if available
Badge Colors (in NotificationTile):
- Order Update: Blue
- New Follower: Purple
- Line Reply: Green
- Line Like: Red
- Review Like: Orange
- Stock Alert: Teal
- Club Invite: Indigo
- Club Book Added: Deep Purple
- Challenge Start: Amber
- Challenge Ending: Deep Orange
ActivityFeedItem
Activity feed items use LineCard and ReviewCard based on content type.
Activity Types
The feed renders different components:
- Lines:
LineCardcomponent - Reviews:
ReviewCardcomponent - Notifications:
NotificationTilecomponent
Feed Implementation
// In FeedProvider/SharePage
feedState.when(
data: (items) => ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
final item = items[index];
if (item is Line) return LineCard(line: item);
if (item is Review) return ReviewCard(review: review);
// ...
},
),
)
CommentThread
Comment threads are implemented via LineCard's reply system.
Usage
Replies are displayed when _showReplies is true in parent LineCard.
Features
- Threading: Single level of nesting (parent → replies)
- Reply Input: Text field with send button
- Loading States: Shows spinner while fetching replies
- Error States: Displays error message if fetch fails
- Empty State: "No replies yet" for authenticated users
Styling
Thread Container
- Left border: 2px ink blue at 0.2 alpha
- Left padding: 12px
- Top padding: 12px
Reply Input
- Background:
AppColors.parchment - Border radius: 8px
- Padding: 12px horizontal, 8px vertical
- Max lines: 3, min lines: 1
LikeButton
Shared button component for likes across Line and Review cards.
Usage
LikeButton(
isLiked: item.isLikedByMe,
count: item.likeCount,
onToggle: () => toggleLike(),
)
Props
| Property | Type | Required | Description |
|---|---|---|---|
isLiked | bool | Yes | Current like state |
count | int | Yes | Number of likes |
onToggle | VoidCallback | Yes | Callback when toggled |
Features
- Animation: Scale animation from 1.0 to 1.3 on tap
- Icon: Filled heart when liked (red), outlined when not
- Count Display: Only shows count if > 0
- Duration: 200ms animation
Styling
- Icon size: 20px
- Liked color:
Colors.red - Unlike color: Theme default
- Padding: 8px horizontal, 4px vertical
- Border radius: 20px (circular ripple)
BookMiniChip
Internal component used in LineCard and ReviewCard for book references.
Anatomy
- Thumbnail: 32x48px book cover
- Title: 2-line max,
AppTypography.bookTitleSmall - Authors: 1-line max, 11px font size
- Container: Rounded 8px, surface container color
- Padding: 8px all
Behavior
- Tappable to open BookInfoOverlay
- Fallback icon if no thumbnail
Common Patterns
Interaction Flows
Like Flow
- User taps LikeButton
- Animation plays (scale up/down)
- API call to like/unlike service
- Feed provider refreshes
- UI updates with new count
Reply Flow
- User taps reply button
- Reply section expands
- User types in input field
- Submit button posts reply
- Reply appears in nested list
Edit Flow (LineCard only)
- Author taps Edit in menu
- TextField replaces content
- User edits text
- Save updates via lineService
- Feed refreshes with new content
State Management
All social components use Riverpod providers:
feedNotifierProvider: Main activity feedlineRepliesNotifierProvider: Thread replieslineServiceProvider: Line CRUD operationsreviewServiceProvider: Review operationsauthNotifierProvider: User authentication state
Error Handling
Components show SnackBar messages for:
- Failed like/unlike operations
- Failed reply submissions
- Failed content updates
- API errors
Typography
- Card Heading:
AppTypography.cardHeading - Card Body:
AppTypography.cardBody - Card Caption:
AppTypography.cardCaption(timestamps, metadata) - Card Label:
AppTypography.cardLabel(buttons, badges)
Color Palette
- Ink Blue:
AppColors.inkBlue(primary text, icons) - Parchment:
AppColors.parchment(reply backgrounds) - Forest Green:
AppColors.forestGreen(success messages) - Coral Spine:
AppColors.coralSpine(error messages) - Teal Edge:
AppColors.tealEdge(primary buttons)