mysampark_chat 1.3.0 copy "mysampark_chat: ^1.3.0" to clipboard
mysampark_chat: ^1.3.0 copied to clipboard

Official MySampark Chat Widget for Flutter. Add AI-powered live chat with human agent takeover, typing indicators, lead forms, and real-time WebSocket support.

1.3.0 #

  • Major Feature: Global SDK Background Initialization Added MySamparkChat.initializeBackground() to support standalone global chat tracking, allowing unread badges and popup notifications across any screen.
  • Major Feature: In-App Notification Banners New incoming messages trigger a branded, globally visible top banner when the chat screen is closed, simply by passing navigatorKey to the SDK initialization.
  • Major Feature: "Now Live" Presence Tracking Added MySamparkChatObserver. Dropping this into your MaterialApp automatically syncs the visitor's currently viewed screen with the "Now Live" Admin Dashboard (via a dedicated visit WebSocket channel), identical to the web widget behavior.
  • Fixed: Fixed a critical routing bug where tapping the new notification banner would open the Chat Screen with default properties instead of preserving the custom baseUrl or user identity passed during initialization.

1.3.0 #

  • A human agent who takes a chat over is now named and shown, instead of staying anonymous behind the business's name. Their photo and name replace the logo and title in the chat header for as long as they hold the chat, sign each of their own bubbles, and appear on the typing indicator as "Hemangi is typing" rather than bare dots. The header goes back to the business the moment they hand it over. An agent with no profile picture gets their initial in a coloured circle, never a broken image.
  • Added ChatAgent — id, name, avatarUrl and an initial for the placeholder.
  • Added ChatMessage.agent, set on agent-role messages the backend attributed. Null for visitor and assistant messages, and for agent messages from before this existed, which keep the old "Support Agent" label.
  • Added ChatService.activeAgentStream and ChatService.activeAgent — who has the conversation right now, null for the AI. Use it to put the person in your own header if you don't use MySamparkChatScreen. An AI reply counts as null, which is also how a takeover that quietly expired on the server clears itself on the client.
  • Added ChatService.typingAgentStream — who the current typing indicator belongs to, null when it is the AI thinking. Emitted just before typingStream on each start, so a listener watching both always has the right name by the time the dots appear.
  • The AI's waiting state now says what it is waiting for. Three dots covered everything from a one-second answer to a minute-long booking turn, which reads as a hung app; the bubble now carries a line of text, shimmer bars roughly the size of the answer so the thread doesn't jump when it lands, and copy that admits it is slow once the wait passes 7 and 18 seconds. A backend that pushes a status with its typing tick ("Checking available slots…") replaces that copy with the real thing.
  • Added ChatService.assistantStatusStream — what the AI is doing right now, or null. Only emitted by backends that send it; older ones never do and the UI falls back to its own copy.
  • The send button no longer turns into a spinner while waiting. It dims instead: a second spinner on the control the visitor just pressed said "stuck", not "coming", and the thread already shows the wait where the answer will appear.
  • Added MessagePayload.quickReplies, rendered as tappable chips under the newest reply. A booking turn used to read back twenty numbered time slots and ask the visitor to "reply with the number"; now they tap one. Chips send their label verbatim, go through the same pre-chat survey gate as typing, and clear as soon as the conversation moves on. Backends that don't send quick_replies are unaffected.
  • Added ChatService.reportTyping(draft) and ChatService.stopTyping(). MySamparkChatScreen already calls them, so the agent sees the visitor composing and the first 500 characters of what they are writing, and can start on the answer before the question arrives. Safe to call per keystroke: ticks are throttled to one every two seconds, with a trailing one shortly after typing stops.
  • typingStream keeps its Stream<bool> shape, so nothing existing breaks — the agent's identity arrives on the new streams beside it.
  • Requires a backend with agent attribution (active_agent on /history, agent on agent messages, agent_joined / agent_left). Older backends send none of it and the chat behaves exactly as in 1.2.4.
  • Fixed: product and offer cards disappeared from every reply as soon as the chat was reopened. /history returns the cards beside the stored reply rather than inside it, and only the reply was being read — so the thread came back as plain text. Both places are read now, the reply's own cards still winning when it has them.
  • Fixed: message times on a reloaded chat were shown in UTC. The backend sends UTC, the package now converts to the device's zone — an IST visitor was seeing every restored bubble 5.5 hours early, while live ones (built from DateTime.now()) were correct, so the same thread disagreed with itself.
  • Fixed: scrolling up to the top of a long chat loaded nothing, while sitting at the bottom loaded page after page. The thread is a reversed list, so "near offset 0" is the newest message, not the oldest; older pages are now fetched when the visitor actually reaches the top.
  • Fixed: a bare www.example.com link in a reply opened nothing — the scheme was being added by replacing the URL with https:// instead of prefixing it, which threw the host away.
  • Fixed: wsUrl no longer defaults to production. Left unset it follows baseUrl, so a staging or self-hosted backend opens its own socket instead of production's; the backend's advertised ws_url is preferred when it is on that same host, matching the web widget. Production resolves to exactly the URL that used to be hardcoded, so nothing changes for apps on the default baseUrl. Pass an empty string to turn the live connection off.
  • Fixed: a TapGestureRecognizer was created for every link on every rebuild and never disposed. They are cached per URL now and disposed with the screen.
  • Fixed: submitting the lead form or pre-chat survey, or picking an image, could call setState() after the chat had been closed.
  • Fixed: when a reply arrived with no readable text, the bubble printed the raw reply object ({type: text, message: …}). It falls back to the backend's own reply_text instead.
  • Prices now group thousands (₹97,500, not ₹97500), the way the web widget already did, using a fixed pattern so the same card reads the same on every device.
  • Added WidgetConfig.wsUrl and ChatService.defaultWsUrlFor(baseUrl).

1.2.4 #

  • Fix missing confirm escalation buttons due to WebSocket fallback logic.

1.2.3 #

  • Added userPhone, userTags and userProperties to MySamparkChatScreen, MySamparkChatBubble and ChatService, sent as user_phone, user_tags and user_properties — the same visitor details the web widget now accepts through window.MySamparkIdentify / MySamparkChat.identify(). Tags add to the visitor's existing tags; properties merge key by key, and a null value removes that key. Requires a backend with the visitor_tags / visitor_properties migration; older backends ignore the fields.
  • Added ChatService.resetVisitor(widgetKey) — call it on logout (the web widget's MySamparkChat.reset()). It clears the stored session, conversations and survey flag for that widget, closes every open connection for it, and makes an open chat screen or bubble start over as a new anonymous visitor. Before this, the session ID lived for the life of the install, so a bubble left mounted after logout kept the previous user's socket open and could show their agent's replies as notifications to whoever used the device next. The backend never handed one user's identified conversation to another; this closes the client side.
  • MySamparkChatScreen and MySamparkChatBubble now restart when the host app passes a different userId / userHash (login, logout or a user switch while they're mounted). Previously both kept the identity they were first built with until disposed.
  • The pre-chat survey is skipped when the app already passed a name, email or phone, matching the web widget. It used to be skipped only for a verified login or details the backend already had.
  • A malformed userEmail is now dropped (with a debug message) instead of being sent. The backend rejects the whole request on an invalid email, which stopped the chat from loading at all.
  • Text and icons on the brand colors (headers, visitor bubbles, buttons, launcher, offer badges) now switch to dark on light colors instead of always being white — white stays while it has at least 3:1 contrast, the same rule as the web widget. A light green or orange widget no longer has white-on-light text.
  • Fixed: the pre-chat survey avatar drew a white icon on a 10% tint of the action color, so it was nearly invisible. It now uses the action color.
  • Deprecated ChatService.generateHash. The hash must be computed on your own backend; running it in the app means shipping the widget secret inside the APK/IPA. It still works and will be removed in 2.0.0.

1.2.2 #

  • Added a "Select" button to product cards, shown when the backend sends select_products: true on a reply (only for widgets that have a booking-style action/sequence which actually uses the id it sends back — a plain Q&A bot's cards are unaffected). Tapping it sends [ProductCard.id] back as selected_product_id on the next message, so the backend settles which item the conversation is about exactly, instead of guessing it back from the product name as plain text. Distinct from the existing "View product" button, which still opens the product itself (in-app via onProductTap, or the browser).
  • ChatService.sendMessage() takes an optional selectedProductId parameter, sent as selected_product_id.
  • Added MessagePayload.selectProducts, parsed from select_products. Requires a backend that sends it; older backends simply leave it false and no Select button renders.

1.2.1 #

  • Added ProductCard.features — vendor/sku/barcode/attributes as synced from Shopify/WooCommerce/the push API. Null for a manually-entered product or one with no synced attributes. Requires a backend that sends features on products_referenced cards; older backends simply leave it null.
  • Added ProductCard.raw — the card exactly as the backend sent it, so a host app can read a field this class doesn't model yet without waiting on a package update.

1.2.0 #

  • Added onProductTap to MySamparkChatScreen and MySamparkChatBubble — a product card can now open inside the host app instead of throwing the visitor out to a browser. Return true from the callback and the package does nothing further; return false, or leave it unset, and the card's URL opens exactly as before, so an app only writes code for the products it actually stocks. The BuildContext passed in is the chat's own, which is what pops the bubble's bottom sheet — the host app's context can't, and pushing from it leaves the product page hidden behind the sheet.
  • Added ProductCard.externalId and ProductCard.source — the merchant's own id for the product and which catalogue it came from (api, shopify, woocommerce). ProductCard.id has always been MySampark's internal id, which a host app can't match against its own catalogue; externalId is the one to look up. Null for products the merchant typed in by hand, and for cards restored from conversations that predate this release, both of which fall back to the browser on their own.
  • A product card with no URL is now tappable when onProductTap is set, so an app-only listing can still open — previously the whole card and its button were hidden without a link.
  • Requires a backend that sends external_product_id on products_referenced. Older backends simply leave it null.
  • Fixed: every non-INR price rendered with a bare $. ProductCard.formattedPrice had one branch — ₹ for INR, $ for everything else — so a Singapore merchant's SGD 48 card read as US dollars, and so did AUD, CAD, HKD and NZD. Prices now carry their regional prefix (S$, A$, C$, NZ$, HK$, NT$, R$, MX$), the major non-dollar symbols are listed too, and an unlisted currency falls back to its ISO code (MYR 48) rather than guessing. intl's NumberFormat.simpleCurrency is not used for this — its own table maps SGD, AUD, CAD, HKD and NZD all to a bare $.
  • Fixed: the header ignored the merchant's support hours. support_online has always arrived on init() and been parsed into WidgetConfig.supportOnline, but nothing read it — the status dot reflected only whether the WebSocket was connected. A merchant who marked Sundays closed saw "Offline" on their own website widget and "Online" here. The status now combines both, exactly as the web widget does.
  • Fixed: "talk to a human" buttons appeared outside support hours. A confirm_escalation reply rendered its Yes/No buttons whenever it was on screen, including when replayed from history after closing time — offering the visitor a handoff nobody was there to take. They now render only while support is online.

1.1.8 #

  • Fixed: product cards never rendered in chat. The backend sends products_referenced alongside a product_list / product_detail reply, and the reply text is only an introduction — "Here are some products currently available: A, B, C." — so the app showed that sentence and nothing else, with no picture, price or link. Cards now render under the reply as a horizontal carousel, matching the web widget.
  • Fixed: offer cards never rendered in chat. Same cause, worse symptom: an offer_list reply's text is "Here are our current offers:" and the cards were dropped, leaving a bubble that ended on a colon. In-chat offers now use the same tile as the Offers tab. (The Offers tab itself was unaffected — it loads from /offers separately.)
  • Fixed: merchant-defined Track Order fields were ignored. order_tracking_extra_fields arrives on init() and the web widget renders one input per entry, sending them back under params. This package rendered none and sent none, so a merchant whose order API requires an extra field (a postcode, a phone number) got an incomplete request and the visitor got "we couldn't find that order" for a correctly filled form. Shopify-backed order tracking was never affected — that path takes no extra parameters.
  • Added ProductCard and OrderTrackingField models, and exported MessagePayload, MessageHighlight, MessageSection and MessageCta — all four were already reachable through ChatMessage.payload without being nameable.
  • ChatService.trackOrder() takes an optional params map.

1.1.7 #

  • pub.dev score maintenance, no behavior changes:
    • Added dartdoc comments across the public API (MySamparkChatBubble, MySamparkChatScreen, ChatService, and all exported models) for the pub.dev "Provide documentation" score.
    • Bumped intl to ^0.20.3 and flutter_lints to ^6.0.0 (up-to-date dependencies score).
    • Fixed all analyzer lints flagged by flutter_lints 6.0.0 (withOpacity → withValues, unnecessary_library_name, curly_braces_in_flow_control_structures, string concatenation → interpolation) and applied dart format.

1.1.6 #

  • Fixed: MySamparkChatBubble's in-app notification banner could pop up on top of a MySamparkChatScreen the visitor already had open, if that screen was opened some other way than the bubble's own _openChat() (e.g. a host app's own "Support" tab doing its own Navigator.push) — the bubble only tracked whether it had opened the chat, with no way to know a different screen instance was already showing that exact message live.
  • Added MySamparkChatScreen.isAnyScreenOpen — tracks whether any instance is currently mounted, regardless of how it was opened. The bubble now checks this alongside its own state before showing the banner or incrementing the unread badge.

1.1.5 #

  • Fixed: conversation starters now render on the Home tab (a card-style list above Offers/Chat/Track, matching the web widget), instead of only as chips inside an already-empty chat view. Tapping one switches to the Chat tab and sends it immediately, going through the same pre-chat survey gate as a normal message.
  • Removed the old chat-view starter chips row — the web widget never had this either; starters live on Home only.

1.1.4 #

  • Guest-to-login merge: a visitor's session_id is no longer cached per-identity, so a guest who logs in mid-session keeps the same session_id and the backend now merges their guest conversation into their identified thread instead of starting a disconnected second one.
  • Backend: init(), message(), and trackOrder() all guard this merge against a shared/reused device — a session_id match is only adopted if it isn't already a different identity's conversation, so logging out and having someone else use the same device (or a plain anonymous visitor after that) can never inherit the previous person's thread, name, or email. submitLead() got the equivalent guard against overwriting an already-identified visitor's details.

1.1.3 #

  • Fixed: is_identified from the backend now also reflects this request's own HMAC verification, not just an existing conversation's persisted flag — a first-time logged-in visitor (verified but with no conversation yet, since those are only created lazily) was incorrectly treated as anonymous, so they'd see the pre-chat survey and the order-tracking email field even though they were already identified.
  • Fixed: trackOrder() now sends session_id and the visitor's identity params (user_id/user_hash/user_name/user_email) — required by the backend's /track-order fallback path for visitors who reach "Track your order" before ever sending a chat message. Without this, that path could never be reached (missing session_id failed validation first), and even once reached, an identified visitor's freshly-created conversation had no email attached, causing a dead-end "Email is required" error with no visible field to fix it.

1.1.2 #

  • MySamparkChatScreen now mirrors the web widget's close behaviour: if a conversation was started, its WebSocket stays open for a 5-minute grace period after the screen closes instead of disconnecting immediately (ChatService.scheduleGraceClose()). Screens with no started conversation still disconnect right away.
  • Redesigned the Offers card: tinted header, a highlight badge, and the description's meta facts (min order, usage limit, etc.) now render as scannable pill badges instead of stacked plain-text lines.
  • OfferItem gained a badge field (e.g. "10% OFF", "FREE SHIPPING") — set by the backend from the actual discount data, not guessed from free text on the client.

1.1.1 #

  • ChatService WebSocket connection now matches the web widget's resilience pattern: capped auto-reconnect (max 5 attempts, exponential backoff up to 16s) instead of giving up permanently on onDone/onError.
  • Added a 25s ping keepalive while connected.
  • Added a manual-close flag so an intentional disconnectWebSocket()/dispose() doesn't trigger a reconnect attempt.
  • Fixes MySamparkChatBubble's in-app notification banner going silent after the first WebSocket drop (app backgrounded, network blip, etc).

1.1.0 #

  • Home tab — MySamparkChatScreen now opens on a branded greeting screen with Offers / Chat / Track Order cards, matching the web widget's layout.
  • Offers card — fetches live deals/discount codes from GET /api/chatbot/offers, tap-to-copy code.
  • Order tracking card — order lookup form (POST /api/chatbot/track-order) showing status, carrier, and tracking link; skips the email prompt for HMAC-identified users.
  • WidgetConfig gained homeGreetingTitle, homeGreetingSubtitle, showOffers, showOrderTracking, and now correctly reads action_color from the backend instead of always falling back to primary_color.
  • New exported models: OfferItem, OrderTrackResult.
  • Home / Chat bottom navigation; hidden while the pre-chat survey or an Offers/Order-Track sheet is open so it can't be used to bypass a non-skippable survey.

1.0.1 #

  • Simplified documentation for cleaner Flutter integration.

1.0.0 #

  • Initial release
  • Full-screen chat screen (MySamparkChatScreen)
  • Floating bubble launcher (MySamparkChatBubble)
  • AI-powered replies with human agent takeover
  • Real-time WebSocket support for live agent messages
  • Pre-chat survey gate (admin controlled)
  • In-chat lead form (name/email/phone)
  • Conversation starters / quick-reply chips
  • Typing indicator with 3-dot bounce animation
  • Chat history with scroll-up pagination
  • Online/Offline status display
  • Logo, colors, and all settings synced from admin dashboard
  • HMAC-SHA256 identity verification for logged-in users
  • Session persistence via SharedPreferences
0
likes
160
points
647
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Official MySampark Chat Widget for Flutter. Add AI-powered live chat with human agent takeover, typing indicators, lead forms, and real-time WebSocket support.

Homepage
Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

crypto, emoji_picker_flutter, flutter, http, image_picker, intl, shared_preferences, url_launcher, uuid, web_socket_channel

More

Packages that depend on mysampark_chat