kreiseck_chat 0.14.0
kreiseck_chat: ^0.14.0 copied to clipboard
Reusable, backend-agnostic chat UI widgets and models for Flutter apps.
kreiseck_chat #
Reusable, backend-agnostic chat UI widgets and models for Flutter apps.
This package contains only UI and plain data models — no networking, storage,
or vendor-specific logic. Wire it up to whatever transport (REST, sockets,
a database, ...) your app already uses by feeding it lists of ChatMessage
and ChatConversation and handling the onSend/onOpen callbacks.
Features #
- Models —
ChatMessage,ChatConversation,ChatParticipant,ChatPresence,ChatAttachment,MessageReaction,ChatMessageRef,TypingState: immutable data classes withcopyWithand value equality.ChatMessagecarries an optionalsender(for group threads), typedattachments, areplyToreference,reactions, and delivery/read timestamps — pluschannel,errorText,kind,translation, andheadline(see below).ChatConversationcarrieschannels, a list ofChatChannelfeeding into it. ChatChannel— a value object describing a channel a message travelled over: an id, display label, icon, and brand color. Ready-made templates —ChatChannel.whatsApp(),.sms(),.email(),.inApp(),.voice()— cover the channels most apps have; override anything viacopyWithto match your own branding. Rendered consistently byChatChannelBadge.ChatCapabilities— a single flag set (reactions,replies,media,typingIndicator,presence,readReceipts) that tells the widgets which affordances a channel actually supports, so the UI never offers something the backend can't do. Built-in profiles:ChatCapabilities.twilioSms()(plain text only),ChatCapabilities.twilioWhatsApp()(media, replies, reactions, read receipts, no typing/presence), andChatCapabilities.inApp()(everything on). Use the default constructor orChatCapabilities.custom(...)for anything in between.ChatTheme— a layered visual configuration composed ofChatColors,ChatTypography,ChatIcons, andChatMotion, plus aBubbleStyle(whatsApp,iMessage,minimal),bubbleRadius, andshowBubbleTail. Ready-made presets:ChatTheme.light(),ChatTheme.dark(),ChatTheme.whatsApp(), andChatTheme.iMessage()(the latter two take abrightness). Override just the sub-config you need; the pre-0.3 flat color getters (accentColor,incomingBubbleColor, ...) are preserved for existing call sites.ChatColorsnow also carrieserrorandwarning.showBubbleTailis off by default in every preset, includingwhatsAppandiMessage— the classic speech-bubble tail is opt-in, not drawn automatically just because a preset is styled after an app that has one.BubbleInk/ChatColors.inkFor— colors that sit on a bubble (message text, muted timestamps/status, quote lines/dividers) are not fixed values:ChatColors.inkFor(bubble)returns aBubbleInkderived from that bubble's own fill color viaBubbleInk.forSurface, so a host picking any customoutgoingBubble/incomingBubblecolor still gets legible text without hand-picking a matching text color. The derived tones follow the polarity of that bubble's own text color (outgoingText/incomingText), so timestamp, quote bar and reply name always match the message text instead of independently chasing raw contrast.lineis guaranteed at least 3:1;textandmutedreach 4.5:1 wherever that polarity allows it, and fall back to the same 3:1 floor where it doesn't — e.g. on the default outgoing blue, white text only reaches 4.07:1, an accepted trade-off for one consistent tone over maximum contrast. SetincomingInk/outgoingInkonChatColorsto override the derivation for a given bubble. The lower-levelreadableOn(surface, desired, {target})andcontrastRatio(a, b)helpers do the same for colors that must keep their own hue (e.g. an error red or the read-tick blue) rather than being replaced outright — used throughout the bubble, channel badge, and banner for exactly that.MessageBubble— timestamp, delivery status icon, sender name/avatar in group threads, quoted replies, reaction chips, and media attachments — each gated byChatCapabilities. Also renders a boldheadlineabove the text, aChatChannelBadgewhen the message has achannel, theerrorTextunder a failed bubble with anonRetrycallback that shows a "Erneut senden" action next to it (omit it to show just the failure reason, with no retry action), and — whentranslationis set — a tap-to-toggle between original text and translation.ChatSystemCard— a centered card for non-message content in the thread: system notes, logged events, summaries. Messages withkind: ChatMessageKind.systemrender as this automatically.ChatBanner— a notice bar (ChatBannerVariant.info/.warning) for states affecting the reply: a restricted channel, a disconnected connection, a locked thread.Composer— an auto-growing text field with a send button, an attach button gated oncapabilities.media, typing-change callbacks, and an optionalleadingwidget (e.g. a channel picker).ChatThreadView— a scrollable message list that groups consecutive messages by sender, inserts date separators, shows aTypingIndicator, auto-scrolls to the newest message, and renders an optionalheader.customMessageBuilderlets the host render its own widget forkind: ChatMessageKind.custommessages (falling back to the normal bubble if it returnsnull);composerBannerandcomposerLeadingare forwarded to the composer;readOnlyhides the composer entirely for archive or supervisory views.ChatHeader— a conversation header with avatar, title, and a presence/typing subtitle.ConversationListView— a conversation inbox list with avatars, presence dots, unread badges, and typing previews.onLongPressopens an action sheet from a row;titleBadgeBuilderrenders a small badge before the title (e.g. a spam marker); each row shows a compact strip of channel badges built fromChatConversation.channelsin the subtitle line (channelBadgestill wins when supplied, thenchannels, then the plainchannelLabeltext).
Installation #
dependencies:
kreiseck_chat: ^0.3.0
Usage #
import 'package:kreiseck_chat/kreiseck_chat.dart';
ChatThreadView(
messages: messages, // List<ChatMessage>, oldest first
onSend: (text) {
// append a new outgoing ChatMessage to your own state/store
},
theme: ChatTheme.iMessage(brightness: Brightness.dark),
capabilities: const ChatCapabilities.inApp(),
)
ConversationListView(
conversations: conversations, // List<ChatConversation>
onOpen: (conversation) {
// navigate to the thread for this conversation
},
theme: ChatTheme.whatsApp(),
capabilities: const ChatCapabilities.twilioWhatsApp(),
)
Channel-aware threads with a restricted composer, a channel picker, and custom message rendering:
ChatThreadView(
messages: messages,
onSend: send,
capabilities: const ChatCapabilities.twilioSms(),
composerBanner: ChatBanner(
text: 'Über SMS sind keine Bilder möglich.',
variant: ChatBannerVariant.warning,
theme: theme, // ChatThreadView can't hand its theme down to a
// pre-built child widget, so pass the same theme explicitly.
),
composerLeading: myChannelPicker,
customMessageBuilder: (m) => m.kind == ChatMessageKind.custom
? MyCallCard(message: m)
: null,
)
See example/lib/main.dart for a self-contained demo gallery that switches
between bubble presets, capability profiles, and light/dark mode against
seeded data (presence, typing, reactions, a reply, channels, translations,
system/custom messages, and a conversation list with pinned rows and channel
badges).
Additional information #
Widgets never hard-code colors; everything is driven through ChatTheme so
apps can support light and dark mode and match a channel's native look
(WhatsApp, iMessage, or a fully custom minimal base) without forking the
widgets. Pair a theme with the ChatCapabilities profile that matches your
transport so the UI only offers what the channel can actually deliver.