flutter_chat_pro 1.0.0
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 withNetworkImage. Native and JavaScript web builds keepvideo_player,audioplayersandcached_network_image. webis now a direct dependency.
Fixed #
- The emoji check in
TextMessageViewpasses 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 aChatPreset(classic,whatsApp,telegram,minimal,cards) and simple options (seed color, bubble radius, shadows and border, message text, font,ChatTileslayout, tile radius, square avatars, wallpaper).customizereaches every part ofChatTheme. 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.ChatScaleandChatStyle.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), orChatScale.byScreen()andChatScale.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.roomBuilderopens a room that keeps the inbox's style;onRoomTapis now optional.ChatStyle.pushandChatStyle.carrykeep the style on other pages and follow later changes.ChatStyle.scaleOfreturns the current scale.context.chatTheme, a shortcut forChatTheme.of(context).ChatRoomView.enableVoiceandChatRoomView.enableAttachmentshide the mic or the attach button, for a text-only chat even when aChatUploaderis set.- Names and avatars from the backend:
ChatPage.userscarries the people of a page (fromfetchRooms,fetchMessagesandfetchAround), theUsersChangedevent pushes live changes from eitherevents()stream, andChatKit.updateUserssets 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, soChatUserResolveris only asked for the rest.ChatRepository.putUsersandChatRepository.userChangesexpose the same flow. PollingRealtimecompares the users of each polled page and emitsUsersChangedfor new or changed ones.- The example app is translated with slang into English, French and Arabic, with a language button. Every
ChatStringsfield, 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) andChatPreset.glass(frosted see-through bubbles and input over an aurora gradient).ChatPreset.valueslists 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_setupdownloads the two files the cache needs on the web (sqlite3.wasm,drift_worker.js) into the app'sweb/, matching the drift and sqlite3 versions in itspubspec.lock. The web demo workflow uses it.InMemoryChatSource: a completeChatSourcekept 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,typingandpresencesimulate the other side.- Field names for every model:
AttachmentJsonKeys,RoomJsonKeys(withMemberJsonKeysfor members) andUserJsonKeys, nested inChatJsonKeysasattachmentKeys,roomKeysanduserKeys.ChatRoom.fromJson,RoomMember.fromJsonandChatUser.fromJsontakekeys.ChatJsonKeys.camelCase(and acamelCasepreset on each key set) reads APIs that writeroomId,createdAt,remoteUrl,avatarUrl,lastReadAt. The cache keeps the default names, so no migration. ChatJsonCheck.message,.roomand.usercheck 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.resyncOnResumeturns it off. - Live streams that fail or end are subscribed again with backoff, then the room catches up.
ChatKit.syncErrorsreports 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 callsChatKit.onAuthExpired.retryPending()resumes. Attachment.openRead()andreadAsBytes()read a picked file on every platform, including the web, whereFile(localPath)fails. A file the browser forgot after a reload fails withOutbox.fileUnavailableand showsChatStrings.fileUnavailableinstead of retrying forever.- Push notifications:
ChatKit.activeRoomIdis the room on screen, to skip its foreground notification.doc/push.mdcovers Firebase Messaging end to end: payload, background handler, opening the room from a tap after a cold start, badge, and iOS limits. PagedMessagesturns an API that pages by number or offset (?page=3) intofetchMessages, 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) atimageQuality(80), and iPhone HEIC photos become JPEG. GIFs keep their real type.DefaultAttachmentPickertakes 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-onlyAttachment.thumbnailPathand shown while the video uploads. When the uploader returns nothumbnailUrl, the poster is uploaded too and its URL is sent. ChatConfig.compressVideoruns the app's compressor (for examplevideo_compress) before a video uploads. The bubble showsChatStrings.compressing; a throw sends the original.maxAttachmentBytesis checked on the compressed file, and a file still too big fails withOutbox.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
Messagehierarchy (text, image, video, audio, file, system, custom),ChatRoom,RoomMemberread pointers,Attachment, keyset cursors,ChatEvent, and a configurable JSON codec (ChatJsonKeys,MessageCodec). - Backend contracts
ChatSource,ChatUploader,ChatUserResolver;ChatKitroot,ChatKitScope, andChatConfig. - Customization surface:
ChatTheme(ThemeExtensionwithColorSchemefallback),ChatStrings,ChatFormatters,ChatBuilders,InboxBuilders,MessageContext,GroupPosition. - Built-in SQLite cache:
ChatCacheinterface andDriftChatCache(one database per user, reactive room and message queries, keyset paging, pending-to-confirmed reconciliation, outbox, drafts, sync state, retention).ChatKitopens and clears it. ChatRepository: cache-first sync with bounded gap fill, keyset paging in both directions, latest and detachedRoomWindows, jump to any message (fetchAroundor paging back), ordered realtime events, reconnect resync, in-memory typing and presence, and batched user lookups with a TTL.OutboxandRetryPolicy: 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.setOnlineandretryPendingdrive 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) andComposerController(draft persistence, reply, edit, staged files, throttled typing).ChatSourcegains optionalsetPinnedandsetMuted. ChatMessageList: a reversed, center-anchoredsuper_sliver_listscroll 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. AlsoMessageRow,ChatAvatarandbuildChatListItems.- Message widgets:
MessageContent(builder resolution: bubble → per type → default),MessageBubblewith group-aware corners,TextMessageView(tappable links, e-mails and phones; read more; large emoji-only),FileMessageView, system, deleted and unsupported views,StatusTickswith semantics and retry,ReplyPreview,ReactionsBar,MessageActionsSheetwith capability-filtered defaults and app actions,SwipeToReply, and selection mode in the list.MessageContextgainscurrentUserId,repliedToAuthor,displayStatusandisSelectionMode. - Media and voice:
ChatMediaStorekeeps media on disk. It downloads each file once with progress, adopts the user's own uploads without a download, evicts LRU files pastChatConfig.maxMediaCacheBytes, exports with "Save" (FilePickerorChatKit.onSaveMedia), and is cleared byclearUserData. Also new:ChatImage;ImageMessageView(1 to 4+ grid with "+N", size reserved before loading);VideoMessageView;AudioMessageView(waveform, seek, 1x / 1.5x / 2x); andMediaViewer(swipe, zoom, video playback, swipe-down to close, save). PlusAudioPlayerHub(one player at a time),VoiceRecorderController(permission, lock, review, discards under 1 s, 40-bar waveform) andChatMediaScope. The cache schema moves to v2 with themedia_filestable. - 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 throughAttachmentOption),StagedAttachments, andVoiceRecordButton(slide to cancel, slide up to lock, review with playback).DefaultAttachmentPickerandattachmentFromXFileread size, MIME type and dimensions. The pickers can be replaced throughAttachmentPicker. - Screens:
ChatRoomView(app bar, optional header, message list and composer; owns aComposerControllerwhen none is given),ChatAppBarwithChatAppBarOptions(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) andRoomAvatar. A "Select" message action starts multi-selection.InboxController.typingNamesandChatRepository.typingChangesbring typing to the inbox. ChatRoomViewappliesChatBuilders.appBarActions,appBarBuilderandcomposerBuilder.ChatStrings.customPreviewgives custom message types an inbox and reply preview.- Several chat lists from one backend:
RoomFilter(types, labels, excluded labels, unread only, a customwhere; presetsdirectandgroups;toQuery()for REST),ChatRoom.labels,kit.inbox(filter:)andInboxController.setFilter. Each controller pages, searches and counts unread on its own;ChatRepository.fetchRoomsis stateless and resync refreshes every open list. The filter reachesfetchRooms(filter:), and the kit filters its cache again, so backends may ignore it;InboxViewkeeps loading while a filtered list is short. The cache schema moves to v3 withrooms.labels_json. - Mixed backends:
ChatSourceis split intoChatDataSource(reads and writes,ChatDataSourceDefaults) andChatRealtime(events and typing).ComposedChatSourcejoins one of each, for example REST data with Firebase, Supabase or WebSocket realtime.PollingRealtimegives a REST-only backend realtime by polling open rooms and the inbox. - Profiles and business accounts:
ChatProfile, andChatProfileSwitcher, 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.ChatProfileScoperebuilds the chat tree on each switch;ChatProfileMenuButtonswitches from the app bar with business badges and unread counts. For businesses answered by several staff members,ChatKit.agentIdis stamped on sent messages asMessage.sentBy(stored in JSON assent_byand 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.MessageContextgainsagentId,sender,isSentByMeandisSentByColleague;RoomContextgainsagentId,lastMessageSenderandlastMessageSentByColleague.ChatKit.disposereleases the audio player it created. - Grouped styling:
ChatThemeholds 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; anyShapeBorder, elevation, divider, margin) andChatBadgeStyle. 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()andfontSize()let app widgets follow it.withMessageText,mapBubblesandmapTextchange many styles at once. New public widgets:ChatUnreadBadgeandChatChip. - Custom messages: the
ChatBuilders.customBuilderresolver picks a widget from the message data (several cards for one type) and returns null for unknown variants;ChatBuilders.bubbledCustomTypesdraws 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
urlis read whenremote_urlis missing. A missingmime_typeis 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 singleattachmentor anattachmentslist. Message.fromJson(json, roomId:)andMessageCodec.decode(json, roomId:)fill in a missingroom_id, as in message list responses. A room'slast_messagetakes the room's id.- A room without
updated_attakes 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
readandreceivedmeanseenanddelivered.MessageStatus.isKnowntells whether a value is understood. - Errors name the message or room, the field and the fix (for example "pass roomId: to Message.fromJson").
- An attachment can be a bare URL string, and
- 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-inChatSource. The quick start starts withInMemoryChatSource, 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 withroomId:. The agent skill covers the new path, keys, checker and demo source. - The example's
tool/web_assets.dartis replaced by the package'sweb_setupcommand. - A
theme:passed toInboxVieworChatRoomViewis scaled by theChatStyleabove 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
ChatStyleand 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
userCacheTtlalso updates open screens. - Catching up a room that missed messages now fetches the newest page first and walks back with
beforeuntil it meets the cache, at mostmaxGapPages(5) requests. Before, it paged forward withafterfrom 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.afteris now only used byPollingRealtimeand after a jump. - The README has a "Media, sync and push" section: photo settings, a
video_compressrecipe, what the kit does on resume, reconnect and expired tokens, push, andPagedMessages. 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.
