Skip to main content

flutter_chat_pro 1.0.0 copy "flutter_chat_pro: ^1.0.0" to clipboard
flutter_chat_pro: ^1.0.0 copied to clipboard

Backend-agnostic chat kit for Flutter: typed models, built-in SQLite cache, offline outbox, controllers, and a fully customizable chat room and inbox UI.

Changelog #

1.0.0 - 2026-10-02 #

First stable release. The API is the same as 0.1.0.

Added #

  • WebAssembly support (flutter build web --wasm). WebAssembly builds play videos and voice notes with the browser's own media elements and load images with NetworkImage. Native and JavaScript web builds keep video_player, audioplayers and cached_network_image.
  • web is now a direct dependency.

Fixed #

  • The emoji check in TextMessageView passes static analysis on every analyzer version.

0.1.0 - 2026-10-02 #

First release: a backend-agnostic chat room and inbox with an offline SQLite cache.

Added #

  • ChatStyle: wrap any part of the app to style and scale every chat widget below it. It takes a ChatPreset (classic, whatsApp, telegram, minimal, cards) and simple options (seed color, bubble radius, shadows and border, message text, font, ChatTiles layout, tile radius, square avatars, wallpaper). customize reaches every part of ChatTheme. The theme is built in a fixed order: preset, options, customize, scale. Nested styles change only what they pass and never scale twice. Sheets and dialogs keep the style.
  • ChatScale and ChatStyle.scale: one size factor and one text factor, recomputed on every resize and rotation. Works with any scale package (ChatScale(1.w, text: 1.sp) for flutter_scale_kit or flutter_screenutil), or ChatScale.byScreen() and ChatScale.fixed() without one. Scales multiply for a zoom setting. The example tests it against the real flutter_scale_kit on phones, landscape and tablets.
  • InboxView.roomBuilder opens a room that keeps the inbox's style; onRoomTap is now optional. ChatStyle.push and ChatStyle.carry keep the style on other pages and follow later changes. ChatStyle.scaleOf returns the current scale.
  • context.chatTheme, a shortcut for ChatTheme.of(context).
  • ChatRoomView.enableVoice and ChatRoomView.enableAttachments hide the mic or the attach button, for a text-only chat even when a ChatUploader is set.
  • Names and avatars from the backend: ChatPage.users carries the people of a page (from fetchRooms, fetchMessages and fetchAround), the UsersChanged event pushes live changes from either events() stream, and ChatKit.updateUsers sets them from app code. The kit saves them in the cache, replaces them when they change, and updates open inboxes and rooms at once. Users that arrive this way count as fresh, so ChatUserResolver is only asked for the rest. ChatRepository.putUsers and ChatRepository.userChanges expose the same flow.
  • PollingRealtime compares the users of each polled page and emits UsersChanged for new or changed ones.
  • The example app is translated with slang into English, French and Arabic, with a language button. Every ChatStrings field, the example screens, the custom cards, plurals and dates follow the language, and Arabic is right to left. A test checks that no chat text is left in English.
  • The example inbox menu has "Reset demo": it clears every profile's cached data with ChatProfileSwitcher.clearAllUserData, restarts the fake backend with its sample chats, comes back online on the personal profile and resets the style, so demos can be recorded again and again.
  • The example has an incoming messages button (inbox and room app bars): while on, the fake backend has people type and then send texts or photos every few seconds in random chats, on both profiles.
  • Four presets inspired by today's chat apps: ChatPreset.whatsAppNew (pill bubbles without tails, frameless photos, a composer floating on the wallpaper, as in the 2026 WhatsApp redesign), ChatPreset.iMessage (blue and grey bubbles, outlined input), ChatPreset.messenger (blue to pink gradient bubbles) and ChatPreset.glass (frosted see-through bubbles and input over an aurora gradient). ChatPreset.values lists all nine.
  • The example has a style shuffle for demos: a shuffle button in the app bars switches automatically to the next preset every 3 seconds, with a new color, sometimes dark mode and random bubble and row shapes. The style sheet also has "Random style" for a single change. The app bar buttons are smaller so they all fit.
  • A live web demo of the example at https://fodilfliti.github.io/flutter_chat_kit/, deployed to GitHub Pages by .github/workflows/deploy_web.yml. In a browser and on desktop the example runs inside device_preview's phone frame. The example's profile photos come from a host that sends CORS headers, so they show on the web too.
  • dart run flutter_chat_pro:web_setup downloads the two files the cache needs on the web (sqlite3.wasm, drift_worker.js) into the app's web/, matching the drift and sqlite3 versions in its pubspec.lock. The web demo workflow uses it.
  • InMemoryChatSource: a complete ChatSource kept in memory, to see and style the whole chat before writing backend code. InMemoryChatSource.sample(currentUserId:) comes with rooms, people and messages; it pages newest first, sends idempotently, edits, deletes, marks read, reacts, pins, mutes, emits live events and can auto reply with a read receipt and typing first. receive, typing and presence simulate the other side.
  • Field names for every model: AttachmentJsonKeys, RoomJsonKeys (with MemberJsonKeys for members) and UserJsonKeys, nested in ChatJsonKeys as attachmentKeys, roomKeys and userKeys. ChatRoom.fromJson, RoomMember.fromJson and ChatUser.fromJson take keys. ChatJsonKeys.camelCase (and a camelCase preset on each key set) reads APIs that write roomId, createdAt, remoteUrl, avatarUrl, lastReadAt. The cache keeps the default names, so no migration.
  • ChatJsonCheck.message, .room and .user check a real backend response and list each field the kit can't read, or reads with a guess, with the fix: missing fields, epoch seconds, dates without a time zone, unknown status or type, attachments without a URL, guessed mime types, images without a size, voice notes without a duration.
  • Back from the background: after ChatConfig.resumeResyncAfter (5 s) the kit reconnects dropped live streams, fetches what open rooms and inbox lists missed, and sends what is queued. ChatConfig.resyncOnResume turns it off.
  • Live streams that fail or end are subscribed again with backoff, then the room catches up. ChatKit.syncErrors reports failed streams and catch-ups; ChatRepository.reconnect() reconnects by hand.
  • Expired sessions: when the source or uploader throws AuthFailure, the outbox pauses instead of failing every message and calls ChatKit.onAuthExpired. retryPending() resumes.
  • Attachment.openRead() and readAsBytes() read a picked file on every platform, including the web, where File(localPath) fails. A file the browser forgot after a reload fails with Outbox.fileUnavailable and shows ChatStrings.fileUnavailable instead of retrying forever.
  • Push notifications: ChatKit.activeRoomId is the room on screen, to skip its foreground notification. doc/push.md covers Firebase Messaging end to end: payload, background handler, opening the room from a tap after a cold start, badge, and iOS limits.
  • PagedMessages turns an API that pages by number or offset (?page=3) into fetchMessages, without duplicates when new messages shift the pages. It remembers where each room's last page ended, so scrolling back costs one request per page.
  • Photos from the default picker are scaled to ChatConfig.imageMaxDimension (1920) at imageQuality (80), and iPhone HEIC photos become JPEG. GIFs keep their real type. DefaultAttachmentPicker takes both limits.
  • Videos get a poster as soon as they are picked on Android, iOS and the web (with stream_thumbnail), kept in the new local-only Attachment.thumbnailPath and shown while the video uploads. When the uploader returns no thumbnailUrl, the poster is uploaded too and its URL is sent.
  • ChatConfig.compressVideo runs the app's compressor (for example video_compress) before a video uploads. The bubble shows ChatStrings.compressing; a throw sends the original. maxAttachmentBytes is checked on the compressed file, and a file still too big fails with Outbox.fileTooLarge.
  • ChatKit.serverNow(): the device clock corrected by the server's time on confirmed sends. Pending messages use it, so a phone with a wrong clock no longer sorts them above newer replies.
  • Docs: doc/backend_json.md, the JSON contract (every message type, attachments, rooms, members, users, pages, value formats, what is forgiven, what the server receives on send, and a "minimum vs nice to have" table); doc/adapters/your_api.md, a step-by-step guide to plug in an existing API (endpoint mapping, keys, camelCase, mappers for nested JSON, checks, realtime options, uploads).
  • Models: sealed Message hierarchy (text, image, video, audio, file, system, custom), ChatRoom, RoomMember read pointers, Attachment, keyset cursors, ChatEvent, and a configurable JSON codec (ChatJsonKeys, MessageCodec).
  • Backend contracts ChatSource, ChatUploader, ChatUserResolver; ChatKit root, ChatKitScope, and ChatConfig.
  • Customization surface: ChatTheme (ThemeExtension with ColorScheme fallback), ChatStrings, ChatFormatters, ChatBuilders, InboxBuilders, MessageContext, GroupPosition.
  • Built-in SQLite cache: ChatCache interface and DriftChatCache (one database per user, reactive room and message queries, keyset paging, pending-to-confirmed reconciliation, outbox, drafts, sync state, retention). ChatKit opens and clears it.
  • ChatRepository: cache-first sync with bounded gap fill, keyset paging in both directions, latest and detached RoomWindows, jump to any message (fetchAround or paging back), ordered realtime events, reconnect resync, in-memory typing and presence, and batched user lookups with a TTL.
  • Outbox and RetryPolicy: persistent, optimistic send, edit, delete and react, with upload progress, exponential backoff, failed state with retry or discard, per-room ordering, and resumption after restart. ChatKit.setOnline and retryPending drive it.
  • Controllers: InboxController (pinned-first rooms, debounced search, paging, pin and mute, unread total), ChatRoomController (cached-first messages, paging, jump with highlight, new-message badge, read marking at the bottom, unread divider, seen-by and effective status, typing, media grouping, selection) and ComposerController (draft persistence, reply, edit, staged files, throttled typing). ChatSource gains optional setPinned and setMuted.
  • ChatMessageList: a reversed, center-anchored super_sliver_list scroll engine that keeps the viewport stable when older pages, newer pages or incoming messages load; policy-based auto-scroll, scroll-to-bottom button with new-message badge, jump to any message with highlight, day separators, unread divider, floating date header, typing indicator and start-of-conversation marker. Also MessageRow, ChatAvatar and buildChatListItems.
  • Message widgets: MessageContent (builder resolution: bubble → per type → default), MessageBubble with group-aware corners, TextMessageView (tappable links, e-mails and phones; read more; large emoji-only), FileMessageView, system, deleted and unsupported views, StatusTicks with semantics and retry, ReplyPreview, ReactionsBar, MessageActionsSheet with capability-filtered defaults and app actions, SwipeToReply, and selection mode in the list. MessageContext gains currentUserId, repliedToAuthor, displayStatus and isSelectionMode.
  • Media and voice: ChatMediaStore keeps media on disk. It downloads each file once with progress, adopts the user's own uploads without a download, evicts LRU files past ChatConfig.maxMediaCacheBytes, exports with "Save" (FilePicker or ChatKit.onSaveMedia), and is cleared by clearUserData. Also new: ChatImage; ImageMessageView (1 to 4+ grid with "+N", size reserved before loading); VideoMessageView; AudioMessageView (waveform, seek, 1x / 1.5x / 2x); and MediaViewer (swipe, zoom, video playback, swipe-down to close, save). Plus AudioPlayerHub (one player at a time), VoiceRecorderController (permission, lock, review, discards under 1 s, 40-bar waveform) and ChatMediaScope. The cache schema moves to v2 with the media_files table.
  • Composer: ChatComposer, with a send / hold-to-record button, Enter to send on desktop and web (Shift+Enter for a new line), Esc to cancel, and reply and edit banners (ReplyEditBanner). Also new: AttachmentSheet (with app options through AttachmentOption), StagedAttachments, and VoiceRecordButton (slide to cancel, slide up to lock, review with playback). DefaultAttachmentPicker and attachmentFromXFile read size, MIME type and dimensions. The pickers can be replaced through AttachmentPicker.
  • Screens: ChatRoomView (app bar, optional header, message list and composer; owns a ComposerController when none is given), ChatAppBar with ChatAppBarOptions (app actions; subtitle shows typing, then presence, then member count), SelectionAppBar (copy, delete, forward callback), InboxView (search, pull to refresh, paging near the end, empty, loading and error states), RoomTile, InboxSearchBar, RoomSwipeActions (pin and mute) and RoomAvatar. A "Select" message action starts multi-selection. InboxController.typingNames and ChatRepository.typingChanges bring typing to the inbox.
  • ChatRoomView applies ChatBuilders.appBarActions, appBarBuilder and composerBuilder. ChatStrings.customPreview gives custom message types an inbox and reply preview.
  • Several chat lists from one backend: RoomFilter (types, labels, excluded labels, unread only, a custom where; presets direct and groups; toQuery() for REST), ChatRoom.labels, kit.inbox(filter:) and InboxController.setFilter. Each controller pages, searches and counts unread on its own; ChatRepository.fetchRooms is stateless and resync refreshes every open list. The filter reaches fetchRooms(filter:), and the kit filters its cache again, so backends may ignore it; InboxView keeps loading while a filtered list is short. The cache schema moves to v3 with rooms.labels_json.
  • Mixed backends: ChatSource is split into ChatDataSource (reads and writes, ChatDataSourceDefaults) and ChatRealtime (events and typing). ComposedChatSource joins one of each, for example REST data with Firebase, Supabase or WebSocket realtime. PollingRealtime gives a REST-only backend realtime by polling open rooms and the inbox.
  • Profiles and business accounts: ChatProfile, and ChatProfileSwitcher, which keeps only the active profile's kit open (own database and media folder), switches safely, feeds connectivity, updates the profile list (clearing removed profiles) and clears every profile on sign-out. ChatProfileScope rebuilds the chat tree on each switch; ChatProfileMenuButton switches from the app bar with business badges and unread counts. For businesses answered by several staff members, ChatKit.agentId is stamped on sent messages as Message.sentBy (stored in JSON as sent_by and in the cache). Colleagues' names show above their messages (ChatConfig.showSentBy) and in inbox previews; only your own messages can be edited; customers see the business. MessageContext gains agentId, sender, isSentByMe and isSentByColleague; RoomContext gains agentId, lastMessageSender and lastMessageSentByColleague. ChatKit.dispose releases the audio player it created.
  • Grouped styling: ChatTheme holds one style per part: ChatBubbleStyle (outgoing and incoming; color or gradient, text and meta styles, radius, tail radius, padding, border, shadows), ChatMessageListStyle (spacing, bubble width, avatars, highlight, background), ChatStatusStyle, ChatChipStyle (date separator, system message, unread divider), ChatReactionStyle, ChatReplyStyle, ChatMediaStyle, ChatComposerStyle, ChatAppBarStyle, ChatAvatarStyle (circle or rounded), ChatRoomTileStyle (plain, divided and card presets; any ShapeBorder, elevation, divider, margin) and ChatBadgeStyle. Every size and color the default widgets draw comes from the theme. scaled(factor, textFactor:) resizes everything for a zoom setting or a screen-size package; size() and fontSize() let app widgets follow it. withMessageText, mapBubbles and mapText change many styles at once. New public widgets: ChatUnreadBadge and ChatChip.
  • Custom messages: the ChatBuilders.customBuilder resolver picks a widget from the message data (several cards for one type) and returns null for unknown variants; ChatBuilders.bubbledCustomTypes draws custom widgets inside the regular bubble with reply preview, time and ticks.
  • Documentation: adapter guides for Firestore, Supabase and REST + WebSocket, a guide for several chat lists and mixed backends, a guide for profiles and business accounts, a customization cookbook, a full README, the consumer agent skill, and an example app on an in-memory fake backend (offline toggle, random failures, filter chips, live style sheet with presets, product offer, quote and booking messages, 5 000-message room, personal and business profiles).

Changed #

  • Decoding forgives what real APIs send:
    • An attachment can be a bare URL string, and url is read when remote_url is missing. A missing mime_type is guessed from the file extension, else from the message type (image/*, video/*, audio/*), so a URL-only image no longer shows as a file. Any media message accepts a single attachment or an attachments list.
    • Message.fromJson(json, roomId:) and MessageCodec.decode(json, roomId:) fill in a missing room_id, as in message list responses. A room's last_message takes the room's id.
    • A room without updated_at takes its last message's time. Members can be plain user ids.
    • Numbers below 100 000 000 000 are read as epoch seconds instead of milliseconds near 1970; numeric date strings work too.
    • Status is read in any case, and read and received mean seen and delivered. MessageStatus.isKnown tells whether a value is understood.
    • Errors name the message or room, the field and the fix (for example "pass roomId: to Message.fromJson").
  • The README's "Connect your backend" is rewritten: a pick-your-path table, the smallest message JSON, what decoding forgives, ChatJsonKeys, camelCase and mapper examples, a filled-in ChatSource. The quick start starts with InMemoryChatSource, web setup is one command, and a new "Troubleshooting" section maps symptoms to fixes. The REST guide links the JSON contract and decodes message pages with roomId:. The agent skill covers the new path, keys, checker and demo source.
  • The example's tool/web_assets.dart is replaced by the package's web_setup command.
  • A theme: passed to InboxView or ChatRoomView is scaled by the ChatStyle above it.
  • The README is rewritten for app developers: a 3-step quick start, styling, and a section on screen-size and theme kits. The agent skill covers ChatStyle and scaling.
  • The README starts with "Before you start": the packages to add, platform setup and the classes you write. New sections show names and avatars from REST and Supabase, and several custom message types at once. The Supabase, REST + WebSocket and Firestore guides show how to send names with pages and push their changes.
  • Resolver results are saved through the same path as backend users, so a refresh after userCacheTtl also updates open screens.
  • Catching up a room that missed messages now fetches the newest page first and walks back with before until it meets the cache, at most maxGapPages (5) requests. Before, it paged forward with after from the cache, which could take dozens of requests and showed old messages first. Past the limit, the fetched pages replace the cached window and older ones load on scroll. after is now only used by PollingRealtime and after a jump.
  • The README has a "Media, sync and push" section: photo settings, a video_compress recipe, what the kit does on resume, reconnect and expired tokens, push, and PagedMessages. The agent skill covers the same, plus wiring the kit into Riverpod providers.

Fixed #

  • Avatar and image load errors (for example HTTP 404) no longer reach FlutterError.onError; the placeholder is shown instead.
  • The example's style sheet shows the preset names in the app language (they stayed in English), and the zoom value shows "×" again.
  • Date separators, the floating date header, inbox times and "last seen" now use the app locale (they were always English).
  • "last seen" no longer shows its prefix twice in the room app bar.

0.0.1 - 2026-10-02 #

Added #

  • Package skeleton to reserve the name. No public API yet.
1
likes
160
points
449
downloads
screenshot

Documentation

Documentation
API reference

Publisher

unverified uploader

Weekly Downloads

Backend-agnostic chat kit for Flutter: typed models, built-in SQLite cache, offline outbox, controllers, and a fully customizable chat room and inbox UI.

Repository (GitHub)
View/report issues

Topics

#flutter #chat #messaging #offline #ui

License

MIT (license)

Dependencies

audioplayers, cached_network_image, collection, cross_file, drift, drift_flutter, file_picker, flutter, http, image_picker, intl, lemsa_core_kit, path, path_provider, record, stream_thumbnail, super_sliver_list, uuid, video_player, web

More

Packages that depend on flutter_chat_pro