fyral_comms 0.4.2
fyral_comms: ^0.4.2 copied to clipboard
Communication feature package for Fleet Glide Admin
fyral_comms #
A premium, responsive, and interactive messaging and team communication package for Flutter applications. Built with modern aesthetics, dark mode adaptability, and native support for both mobile and tablet split-pane layouts.
Features #
- 📢 Compact Broadcast Tile (
broadcastCard/CommsPage): Dedicated compact Broadcast / Announcement header tile with customizable megaphone icon, title, unread counter badges, and tap handlers. - 🗂️ Redesigned Conversation Cards (
conversationCard): Modern chat list tiles featuring synchronized 2-row layout (Title + Timestamp on Row 1, Message + Badge on Row 2), automatic 2-letter title initials avatar with gradient styling, soft drop shadows, and empty message handling. - ✨ Shimmer Skeleton Loading (
ConversationShimmer): Smooth animated linear gradient sweep effect for message bubbles, avatars, and timestamps during initial conversation loading with responsive width handling across all screen sizes. - 📅 WhatsApp-Style Date Separators (
DateSeparatorBadge): Centered floating date badges automatically grouping messages by calendar date ("Today", "Yesterday", and formatted calendar dates). - 🔄 Scroll-to-Top Pagination: Automatically triggers pagination callbacks (
onLoadMoreMessages) when the user scrolls near the top of the chat history, with a sleek top loading indicator pill ("Loading earlier messages..."). - 🔍 Fullscreen Interactive Media Viewer (
FullscreenMediaViewer): Dedicated gallery viewer supporting images and videos. Features pinch-to-zoom and pan viaInteractiveViewer, double-tap quick zoom toggle (1.0x $\leftrightarrow$ 2.5x), horizontal swipe navigation (PageView) with dynamic gesture resolution when zoomed, and integrated video playback controls (video_player). - 🌫️ BlurHash Placeholder Loading: Integrated
flutter_blurhashto render smooth blurred placeholders during remote image network fetching. - 🎬 Automatic Video Thumbnail Previews (
MediaGrid): Responsive multi-attachment grid (1, 2, 3, 4+ items) with automatic first-frame video extraction or explicit poster/thumbnail URLs and translucent play icon badges. - 📷 WhatsApp-Style Media Preview (
MediaPreviewPage): Interactive fullscreen preview for selected or captured photos and videos. Includes pinch-to-zoom, live video preview with play/pause, multi-item swipe navigation, bottom thumbnail gallery strip, embedded Emoji Picker, and caption input. - 📎 Dual-Source Attachment Picker: Popup menu in
MessageBoxsupporting both Camera (image_picker) and Gallery (wechat_assets_picker/pickMultipleMedia) with Android 13+ / 14+ runtime permission handling and automatic fallback. - 📱 Responsive Dual-Pane Split-Screen: Automatically adapts on tablet-sized displays ($\ge 600\text{px}$ in landscape, $\ge 900\text{px}$ in portrait) into a master-detail split-view with an active conversation sidebar and detail message viewport.
- 💬 WhatsApp-Style Replies: Integrated reply preview card nested cleanly inside the message input pill with theme matching, borders, and dismiss controls.
- 👥 Dynamic Mentions Suggestions Overlay: Typing
@displays a filtered user list overlay directly above the input container, presenting usernames and initials-based circular avatars. - 🎨 Rich-Text Mentions Highlighting: Automatically styles active mentions in bold accent text inside message bubbles and on-the-fly inside the text input field.
- 🌓 Full Dark Mode Support: Theme-adaptive color palettes, borders, gradients, reaction badges, and backgrounds across all pages and widgets.
Getting Started #
1. Add Dependency #
Add fyral_comms to your pubspec.yaml:
dependencies:
fyral_comms: ^0.4.1
Or run:
flutter pub add fyral_comms
2. Platform & WeChat Asset Picker Setup #
fyral_comms uses wechat_assets_picker for multi-media gallery selection with WeChat UI aesthetics, alongside image_picker for camera captures. Configure your host application for smooth operation:
Android Configuration (android/app/src/main/AndroidManifest.xml)
Add the required permissions and application settings to your AndroidManifest.xml:
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Storage & Media Permissions -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
<uses-permission android:name="android.permission.READ_MEDIA_VISUAL_USER_SELECTED" />
<!-- Camera Permission for photo & video captures -->
<uses-permission android:name="android.permission.CAMERA" />
<application
...
android:enableOnBackInvokedCallback="true">
<!-- ... -->
</application>
</manifest>
Note:
- Predictive Back Navigation:
android:enableOnBackInvokedCallback="true"is required in your<application>tag for Android 13+ (API 33+) to properly support predictive back gestures and prevent back navigation issues when dismissingwechat_assets_pickergallery screens.- Ensure your
android/app/build.gradlehascompileSdkVersionset to 33 or higher.
iOS Configuration (ios/Runner/Info.plist)
Add the permission keys to your Info.plist:
<key>NSPhotoLibraryUsageDescription</key>
<string>Requires photo library access to pick photos and videos to share in conversations.</string>
<key>NSCameraUsageDescription</key>
<string>Requires camera access to capture photos and videos for messaging.</string>
<key>NSMicrophoneUsageDescription</key>
<string>Requires microphone access to record videos with audio.</string>
Localization Setup (Recommended)
wechat_assets_picker relies on Flutter's localization system to render gallery UI labels (e.g. "Cancel", "Preview", "Send"). Add flutter_localizations to your pubspec.yaml and configure your MaterialApp:
dependencies:
flutter_localizations:
sdk: flutter
import 'package:flutter_localizations/flutter_localizations.dart';
MaterialApp(
localizationsDelegates: const [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: const [
Locale('en', ''),
// Add additional supported locales as needed
],
// ...
);
Automatic Fallback Mechanism
If photo library permissions are restricted or denied on Android/iOS, fyral_comms automatically falls back to the system photo picker (image_picker / pickMultipleMedia()), ensuring an uninterrupted user experience.
Usage Guide #
1. Conversation List View (CommsPage) #
Embed CommsPage in your application route (e.g. using GoRouter or standard Navigator) with optional Broadcast card support at the top:
import 'package:fyral_comms/comms.dart';
CommsPage(
currentUserId: 2,
conversations: conversationGroups,
onConversationSelected: (conversation) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ConversationDetailPage(
title: conversation.name,
// pass parameters or state
),
),
);
},
// Optional Broadcast Card at top of the conversation list:
showBroadcast: true,
broadcastTitle: 'Broadcast',
broadcastMessage: 'Company-wide announcement: All routes updated',
broadcastTime: '10:30 AM',
broadcastUnreadCount: 2,
onBroadcastTap: () {
// Handle broadcast tap
},
)
CommsPage Properties
| Property | Type | Description |
|---|---|---|
conversations |
List<CommsGroup>? |
List of conversation groups to render. |
currentUserId |
int? |
ID of the current user to resolve personal unread counts. |
onConversationSelected |
Function(CommsGroup)? |
Callback when a conversation card is tapped. |
showBroadcast |
bool? (default: false) |
Displays a pinned Broadcast card at index 0. |
broadcastTitle |
String? (default: 'Broadcast') |
Title on the Broadcast card. |
broadcastMessage |
String? |
Subtitle message content on the Broadcast card. |
broadcastTime |
String? |
Formatted timestamp string for the Broadcast card. |
broadcastUnreadCount |
int? (default: 0) |
Unread badge counter for Broadcasts. |
broadcastIcon |
IconData? (default: Icons.campaign_rounded) |
Avatar icon for the Broadcast card. |
broadcastIconColor |
Color? (default: Color(0xFFF97316)) |
Icon tint and avatar background color. |
onBroadcastTap |
VoidCallback? |
Tap callback handler for the Broadcast card. |
broadcastWidget |
Widget? |
Custom widget override for the Broadcast card. |
noDataIcon |
IconData? |
Icon displayed when there are no conversations. |
emptyWidget |
List<Widget>? |
Custom widget list for the empty state. |
2. Conversation Detail View (ConversationDetailPage) #
ConversationDetailPage supports both Controlled (stateless style for BLoC/Riverpod/Redux) and Uncontrolled (stateful fallback) modes.
Uncontrolled Mode (Self-Contained)
ConversationDetailPage(
title: 'Operations Room',
)
Controlled Mode (State-Driven)
ConversationDetailPage(
title: 'Operations Room',
messages: state.messages,
isLoading: state.isLoadingMessages, // Displays ConversationShimmer
isLoadingMore: state.isLoadingMore, // Displays top pagination spinner
hasMoreMessages: state.hasMore,
onLoadMoreMessages: () async {
await context.read<ChatCubit>().loadEarlierMessages();
},
showDateSeparators: true,
isSearching: state.isSearching,
searchQuery: state.searchQuery,
showEmojiPicker: state.showEmojiPicker,
messageController: _messageController,
searchController: _searchController,
focusNode: _focusNode,
mentionableUsers: [
{'id': '1', 'name': 'Sarah Connor'},
{'id': '2', 'name': 'John Doe'},
],
onSendMessage: () => bloc.add(SendMessageEvent()),
onSearchQueryChanged: (query) => bloc.add(SearchChangedEvent(query)),
onToggleEmojiPicker: () => bloc.add(ToggleEmojiEvent()),
onToggleSearch: () => bloc.add(ToggleSearchEvent()),
onClearSearch: () => bloc.add(ClearSearchEvent()),
onMediaPicked: (List<File> files) => bloc.add(MediaPickedEvent(files)),
onBackPressed: () => Navigator.pop(context),
)
ConversationDetailPage Key Properties
| Property | Type | Description |
|---|---|---|
title |
String |
Header title of the conversation. |
messages |
List<dynamic>? |
List of messages to display. |
isLoading |
bool (default: false) |
Displays ConversationShimmer during initial message load. |
isLoadingMore |
bool (default: false) |
Shows top pagination indicator while loading history. |
hasMoreMessages |
bool (default: true) |
Enables/disables scroll-to-top pagination triggers. |
onLoadMoreMessages |
Future<void> Function()? |
Callback triggered when user scrolls near the top. |
showDateSeparators |
bool (default: true) |
Groups messages by date with DateSeparatorBadge. |
mentionableUsers |
List<Map<String, dynamic>>? |
Users suggested when typing @ in the input box. |
emptyTitle |
String? (default: 'No messages yet') |
Title in empty chat state. |
emptySubtitle |
String? |
Subtitle in empty chat state. |
emptyIcon |
IconData? |
Icon in empty chat state. |
emptyPlaceholder |
Widget? |
Custom empty placeholder widget override. |
shimmerPlaceholder |
Widget? |
Custom shimmer placeholder widget override. |
onMediaPicked |
ValueChanged<List<File>>? |
Invoked with selected media files from gallery/camera. |
showMediaPicker |
bool? (default: true) |
Toggles attachment button visibility in MessageBox. |
showBackButton |
bool? |
Controls back button visibility (true to force show on tablet/desktop, false to hide, null for responsive auto). |
forceShowBackButton |
bool? |
Alias for showBackButton: true to guarantee back button display on tablet viewports. |
showAppBar |
bool (default: true) |
Set to false when embedding inside custom layouts. |
addDemoData |
bool (default: true) |
Whether to populate mock messages in uncontrolled mode. |
3. Fullscreen Media Viewer (FullscreenMediaViewer) #
Displays an interactive fullscreen image and video gallery:
import 'package:fyral_comms/comms.dart';
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => FullscreenMediaViewer(
attachments: message.attachments, // URLs, Files, or CommsAttachment objects
initialIndex: 0,
),
),
);
- Pinch-to-zoom & pan: Uses
InteractiveViewerwith smooth double-tap zoom (1.0x $\leftrightarrow$ 2.5x). - Dynamic gesture handling: Resolves swipe conflicts so horizontal panning inside zoomed images does not trigger page swipes.
- Video playback: Built-in player with tap-to-play, center play/pause overlay, and format detection (network, file, assets).
4. Responsive Attachment Grid (MediaGrid) #
Renders 1 to 4+ image and video thumbnails inside chat bubbles with BlurHash support:
import 'package:fyral_comms/comms.dart';
MediaGrid(
attachments: [
'https://example.com/photo1.jpg',
'https://example.com/video1.mp4',
],
isSender: false,
)
5. Media Preview Page (MediaPreviewPage) #
Launches a WhatsApp-style media review and caption screen before sending:
import 'package:fyral_comms/comms.dart';
final MediaPreviewResult? result = await Navigator.push<MediaPreviewResult>(
context,
MaterialPageRoute(
builder: (context) => MediaPreviewPage(
filePaths: ['/path/to/image.png', '/path/to/video.mp4'],
initialCaption: 'Check out these updates',
),
),
);
if (result != null) {
print('Files to send: ${result.files}');
print('Caption: ${result.caption}');
}
6. Conversation Card Tile (conversationCard) #
Stand-alone WhatsApp-style conversation tile widget with automatic two-letter initials avatar:
import 'package:fyral_comms/comms.dart';
conversationCard(
title: 'Operations Group',
message: 'Meeting starts at 10 AM',
time: '9:45 AM',
avatarIconColor: Colors.blueAccent,
unreadCount: 3,
isUnread: true,
onTap: () => openConversation(),
);
7. Broadcast Header Tile (broadcastCard) #
Compact single-line broadcast and announcements banner:
import 'package:fyral_comms/comms.dart';
broadcastCard(
context,
broadcastTitle: 'Broadcast',
broadcastIcon: Icons.campaign_rounded,
broadcastIconColor: const Color(0xFFF97316),
onBroadcastTap: () => openBroadcastChannel(),
);
8. Standalone Shimmer Skeleton (ConversationShimmer) #
import 'package:fyral_comms/comms.dart';
ConversationShimmer(
itemCount: 8,
padding: EdgeInsets.symmetric(horizontal: 14, vertical: 16),
)
8. Date Separator Badge (DateSeparatorBadge) #
import 'package:fyral_comms/comms.dart';
DateSeparatorBadge(
dateText: 'Today',
)
9. Domain Models #
fyral_comms includes strongly typed models with built-in JSON deserialization and serialization:
CommsGroup: Represents a conversation group or topic, withid,name,groupType,participants,lastMessage, andunreadCount.CommsParticipant: Participant details,unreadCount, andlastReadMessageId.CommsUser: User metadata (id,name,email,role).CommsMessage/CommsMessageResponse: Rich message model with text, reactions, attachments, reply references, and delivery/read statuses.CommsAttachment: Attachment metadata includingfileUrl,fileType,fileName,fileSize,thumbnailUrl, andblurhash.
Theming & Dark Mode #
fyral_comms automatically adapts to ThemeData.light() and ThemeData.dark(). For optimal appearance, you can provide custom color schemes:
MaterialApp(
theme: ThemeData(
brightness: Brightness.light,
colorScheme: ColorScheme.fromSeed(
seedColor: const Color(0xFFF97316),
brightness: Brightness.light,
),
),
darkTheme: ThemeData(
brightness: Brightness.dark,
scaffoldBackgroundColor: const Color(0xFF0B1120),
colorScheme: ColorScheme.fromSeed(
seedColor: const Color(0xFFF97316),
brightness: Brightness.dark,
),
),
// ...
);
Example App #
A full demonstration app showing conversation lists, broadcast cards, split-screen tablet navigation, media previews, mentions, shimmer loaders, and theme switching is available in the example/ directory.
To run the example:
cd example
flutter run
Additional Information #
- Repository: Source code and issue tracking on GitHub.
- Contributing: Pull requests, bug reports, and feature suggestions are always welcome!