GiftStore is a module in AtomicXCore specialized in managing the gift function of live streaming rooms. With it, you can build a complete gift system for your live stream application to achieve various revenue and interactive scenarios.Gift Panel | Barrage Gift | Full-Screen Gift |
![]() | ![]() | ![]() |
GiftStore in the following table:Core Concepts | Type | Core Responsibilities and Description |
class | Represents a specific gift data model. It contains the gift ID, name, icon address, animation resource URL and price (coins). | |
class | Represents a gift category, such as "popular" and "luxury". It contains the category name as well as the Gift list under this category. | |
class | Represents the current status of the gift module. Its core attribute usableGifts is a ValueListenable<List<GiftCategory>>, storing the complete gift list fetched from the server. | |
class | Gift event listener, receive gift giveaway event through the onReceiveGift callback. When anyone (including itself) sends a gift, all people in the room will receive this event. | |
class | This is the core management class for interacting with the gift function. Through it, you can fetch the gift list, send a gift, and receive gift events via addGiftListener. |
GiftStore instance and set a listener for receiving gifts and list update events.GiftStore.create(liveId) to get the GiftStore instance bound to the current live streaming room.giftStore.addGiftListener(listener).giftStore.giftState.usableGifts to get gift list updates.import 'package:flutter/foundation.dart';import 'package:atomic_x_core/atomicxcore.dart';class GiftManager {final String liveId;late final GiftStore giftStore;late final GiftListener _giftListener;late final VoidCallback _giftListChangedListener = _onGiftListChanged;// Expose gift event callback externallyvoid Function(String liveID, Gift gift, int count, LiveUserInfo sender)? onReceiveGift;// Expose the gift list externallyValueNotifier<List<GiftCategory>> giftListNotifier = ValueNotifier([]);GiftManager({required this.liveId}) {// 1. Get the instance of GiftStore by liveIdgiftStore = GiftStore.create(liveId);_subscribeToGiftState();_subscribeToGiftEvents();}/// 2. Subscribe to gift eventsvoid _subscribeToGiftEvents() {_giftListener = GiftListener(onReceiveGift: (liveID, gift, count, sender) {// After receiving the event, forward it to external processingonReceiveGift?.call(liveID, gift, count, sender);},);giftStore.addGiftListener(_giftListener);}/// 3. Subscribe to gift list statusvoid _subscribeToGiftState() {giftStore.giftState.usableGifts.addListener(_giftListChangedListener);}void _onGiftListChanged() {giftListNotifier.value = giftStore.giftState.usableGifts.value;}// Call the dispose method to reclaim resources when exiting the live streaming roomvoid dispose() {giftStore.removeGiftListener(_giftListener);giftStore.giftState.usableGifts.removeListener(_giftListChangedListener);giftListNotifier.dispose();}}
GiftCategoryParametersParameter | Type | Description |
categoryID | String | Unique ID of the gift category. |
name | String | Display name of the gift category. |
desc | String | Description of the gift category. |
extensionInfo | Map<String, String> | Extended information field. |
giftList | List<Gift> | Array of Gift objects under this category. |
GiftParametersParameter | Type | Description |
giftID | String | Unique ID of the gift. |
name | String | Display name of the gift. |
desc | String | Description of the gift. |
iconURL | String | Icon URL of the gift. |
resourceURL | String | Resource URL of the gift animation. |
level | int | Gift level. |
coins | int | Gift price. |
extensionInfo | Map<String, String> | Extended information. |
refreshUsableGifts method to fetch gift data from the server.giftStore.refreshUsableGifts() at the appropriate timing (such as after entering the live room).giftStore.giftState.usableGifts in Step 2.extension GiftManagerFetch on GiftManager {/// Refresh the gift list from the serverFuture<void> fetchGiftList() async {final result = await giftStore.refreshUsableGifts();if (result.isSuccess) {debugPrint("Gift list success message");// Upon success, the data is auto-updated via usableGifts listen} else {debugPrint("Gift list failed to pull: ${result.errorMessage}");}}}
sendGift API to send the gift.giftID selected by the user and the number of messages sent (count) from the UI.giftStore.sendGift(giftID:, count:).onReceiveGift.extension GiftManagerSend on GiftManager {/// User sends a giftFuture<void> sendGift(String giftID, int count) async {final result = await giftStore.sendGift(giftID: giftID, count: count);if (result.isSuccess) {debugPrint("Gift $giftID sent successfully");// After the message is sent successfully, everyone including the sender will receive the onReceiveGift event} else {debugPrint("Gift sending failed: ${result.errorMessage}");// You can prompt user here, such as "Insufficient balance" or "Network error"}}}
SendGift API ParametersParameter Name | Type | Description |
giftID | String | Unique ID of the gift to send. |
count | int | The number of sent. |
GiftStore feature heavily depends on your business backend service. This chapter will guide you on how to build a feature-rich, outstanding experience interactive system through server configuration and client implementation.refreshUsableGifts to retrieve configuration data.List<GiftCategory> to render the gift panel.
Interface Category | Interface | Request Example |
Gift Management | Add Gift Information. | |
| Delete Gift Information. | |
| Query Gift Information. | |
Gift Category Management | Add Gift Category Information. | |
| Delete Specific Gift Category Information. | |
| Get Specific Gift Category Information. | |
Gift Relationship Management | Add Relationship between a Specific Gift Category and Gift. | |
| Delete Relationship between a Specific Gift Category and Gift. | |
| Get Gift Relationships under a Specific Gift Category. | |
Gift Multi-language Management | Add Gift Multi-language Information. | |
| Delete Specific Gift Multi-language Information. | |
| Get Gift Multi-language Information. | |
| Add Gift Category Multi-language Information. | |
| Delete Specific Gift Category Multi-language Information. | |
| Get Gift Category Multi-language Information. | |
sendGift.onReceiveGift event; if fails, the completion callback of sendGift receives an error.
Interface | Description | Request Example |
Webhook Configuration - Pre-send Gift Webhook | Allows your backend to validate and approve gift sending (e.g., pre-send checks). |
AtomicXCore itself does not include a gift animation player. You need to select and integrate a third-party library based on business requirements. The following is a comparison of two solutions:Comparison Item | Basic Solution (Svgaplayer_flutter) | Advanced Plan (TCEffectPlayerKit) |
Billing | Free (open-source library) | |
Integration Method | ||
Animation Format Support | SVGA only | SVGA, PAG, WebP, Lottie, MP4, and other formats |
Performance | Recommend SVGA files ≤ 10MB | Support larger animation files, better performance for complex effects, multi-animation concurrency, and low-end devices |
Recommended scenarios | Gift animation format is unified as SVGA with controllable file size | Support multiple animation formats or higher performance/compatibility requirements |
pubspec.yaml file, add dependency and run flutter pub get.dependencies:svgaplayer_flutter: ^2.0.0
GiftStore's addGiftListener.onReceiveGift event is received, check if gift.resourceURL is valid and points to an SVGA file. If so, use SVGAAnimationController to play the animation.import 'package:flutter/material.dart';import 'package:atomic_x_core/atomicxcore.dart';import 'package:svgaplayer_flutter/svgaplayer_flutter.dart';class LiveRoomWidget extends StatefulWidget {final String liveId;const LiveRoomWidget({Key? key, required this.liveId}) : super(key: key);@overrideState<LiveRoomWidget> createState() => _LiveRoomWidgetState();}class _LiveRoomWidgetState extends State<LiveRoomWidget> with SingleTickerProviderStateMixin {late GiftManager giftManager;// SVGA playerlate SVGAAnimationController _svgaController;bool _showAnimation = false;@overridevoid initState() {super.initState();_svgaController = SVGAAnimationController(vsync: this);_setupGiftSubscription();}void _setupGiftSubscription() {giftManager = GiftManager(liveId: widget.liveId);giftManager.onReceiveGift = (liveID, gift, count, sender) {if (gift.resourceURL.isNotEmpty) {_playAnimation(gift.resourceURL);}};}Future<void> _playAnimation(String url) async {try {final videoItem = await SVGAParser.shared.decodeFromURL(url);_svgaController.videoItem = videoItem;setState(() {_showAnimation = true;});_svgaController.forward().whenComplete(() {setState(() {_showAnimation = false;});});} catch (e) {debugPrint("SVGA animation parsing failure: $e");}}@overridevoid dispose() {_svgaController.dispose();giftManager.dispose();super.dispose();}@overrideWidget build(BuildContext context) {return Stack(children: [// Live stream// ...// Full-Screen Gift Animationif (_showAnimation)Positioned.fill(child: SVGAImage(_svgaController),),],);}}
giftStore.addGiftListener.onReceiveGift event is received, extract the sender, gift, and count.BarrageStore.create(liveId) to get the instance bound to the current room.Barrage object, set messageType = BarrageType.text, and textContent as the concatenated string (such as "[sender.userName] sent [gift.name] x [count]").barrageStore.appendLocalTip(giftTip) to insert the message into the local list.// In LiveRoomManager or similar top-level managersvoid _setupGiftToBarrageFlow() {final giftStore = GiftStore.create(liveId);final barrageStore = BarrageStore.create(liveId);final giftListener = GiftListener(onReceiveGift: (liveID, gift, count, sender) {// Concatenate the messagefinal tipText = "${sender.userName} sent ${gift.name} x $count";final giftTip = Barrage(messageType: BarrageType.text,textContent: tipText,);// Optional: Set a special sender// local insertionbarrageStore.appendLocalTip(giftTip);},);giftStore.addGiftListener(giftListener);}
Store/Component | Feature Description | API Reference |
GiftStore | Gift interaction: Get gift list, send/receive gifts, listen to gift events (including sender, gift details). | |
BarrageStore | Danmaku function: send text / custom barrage item, maintain bullet screen list, monitor in real time. |
refreshUsableGifts() to fetch gift data from your backend. These gift data need to be configured in your backend via server-side REST API.GiftStore provides the setLanguage(String language) API. You can call this method before refreshUsableGifts, input the target language code (such as "en" or "zh-CN"). The server will return the gift name and description in the corresponding language based on this language code.onReceiveGift is a broadcast to all members in the room (including the sender). If you perform a UI operation in the success callback of sendGift, and simultaneously execute the same UI operation in the onReceiveGift callback, it can lead to duplication.onReceiveGift event. The returned results of sendGift are only used to process the logic of sending failure (such as prompting the user "sending failure" or "insufficient balance").AtomicXCore connects with your billing system through a backend callback mechanism. The client calls sendGift to trigger the callback. After your backend service completes the charge, it returns the result to the AtomicXCore backend, thereby determining whether to broadcast the gift event.onReceiveGift event) are not affected by muting or message frequency control, ensuring reliable delivery.Feedback