UI Customizations
JoinStories SDK offers different ways to display your widget. There are currently two available triggers:
- Bubbles
- Cards
BubbleWidget
- alias: required identifier; not a UI customization.
Property | Type | Default | Description |
---|---|---|---|
controller | BubbleController? | null | Enables refresh() without rebuilding |
configuration | BubbleConfiguration? | null | Visual/behavior customization (see below) |
BubbleConfiguration
Property | Type | Default | Allowed values | Description |
---|---|---|---|---|
showLabel | bool | true | – | Show label under each bubble |
labelStyle | TextStyle? | null | – | Label fontSize , fontWeight , fontFamily |
labelColor | Color? | null | – | Label color override |
thumbViewSpacing | double | 12.0 | – | Space between bubbles |
thumbViewSize | double | 74.0 | – | Bubble diameter (px) |
loaderColors | List<Color> | [Color(0xFFD9222D), Color(0xFFFFA800)] | – | Loader gradient colors |
loaderWidth | double | 2.0 | – | Loader stroke width |
storyViewedIndicatorColor | Color? | null | – | Color for viewed indicator ring |
showPlayButton | bool | true | – | Show play icon overlay |
animationType | BubbleAnimationType | none | none , pulse | First bubble animation |
fontName | String? | null | – | Platform font override |
labelFontSize | double? | null | – | Label font size override |
maxStories | int? | null | – | Max items (−1 for all) |
customParameters | Map<String, String>? | null | – | Audience targeting params |
horizontalMargin | double? | null | – | Outer horizontal margin |
horizontalPadding | double? | null | – | Inner horizontal padding |
reorderedReadStories | bool? | null | – | Move read stories |
playerBackgroundColor | Color? | null | – | Player background color |
playerVerticalAnchor | String? | null | top , center , bottom | Player vertical alignment |
playerHorizontalMargins | double? | null | – | Player horizontal margins |
playerCornerRadius | double? | null | – | Player corner radius |
playerProgressBarDefaultColor | Color? | null | – | Progress bar base color |
playerProgressBarFillColor | Color? | null | – | Progress bar fill color |
playerProgressBarThickness | double? | null | – | Progress bar thickness |
playerProgressBarRadius | double? | null | – | Progress bar corner radius |
playerStandaloneAnimationOrigin | String? | null | top , topLeft , topRight , bottom , bottomLeft , bottomRight | Standalone open animation origin |
Example
import 'package:join_stories_flutter/join_stories_flutter.dart';
BubbleWidget(
alias: 'widget-alias',
configuration: const BubbleConfiguration(
showLabel: true,
labelColor: Color(0xFF2C3E50),
labelFontSize: 14,
fontName: 'Avenir',
showPlayButton: true,
thumbViewSpacing: 8,
thumbViewSize: 100,
storyViewedIndicatorColor: Color(0xFFE74C3C),
loaderColors: [Color(0xFF3498DB), Color(0xFF2ECC71)],
loaderWidth: 3,
animationType: BubbleAnimationType.pulse,
reorderedReadStories: true,
maxStories: 5,
horizontalMargin: 16,
horizontalPadding: 8,
// Player (standalone) styling used when opening the player from this widget
playerBackgroundColor: Color(0xFF2C3E50),
playerVerticalAnchor: 'center',
playerHorizontalMargins: 20.0,
playerCornerRadius: 12.0,
playerProgressBarDefaultColor: Color(0xFF7F8C8D),
playerProgressBarFillColor: Color(0xFF3498DB),
playerProgressBarThickness: 4.0,
playerProgressBarRadius: 8.0,
playerStandaloneAnimationOrigin: 'top',
),
// Trigger + Player + Analytics callbacks
onTriggerFetchSuccess: (count) {},
onTriggerFetchEmpty: () {},
onTriggerFetchError: (message) {},
onPlayerFetchSuccess: () {},
onPlayerLoaded: () {},
onPlayerFetchError: (message) {},
onPlayerDismissed: (type) {}, // 'auto' | 'manual'
onContentLinkClick: (link) {},
onAnalyticsEvent: (name, payload) {},
);
CardWidget
- alias: required identifier; not a UI customization.
Property | Type | Default | Allowed values | Description |
---|---|---|---|---|
isGrid | bool | false | – | Grid when true; list when false |
controller | CardController? | null | – | Enables refresh() without rebuilding |
configuration | CardConfiguration? | null | – | Visual/behavior customization (see below) |
CardConfiguration
Property | Type | Default | Allowed values | Description |
---|---|---|---|---|
cardRadius | double | 8.0 | – | Card corner radius |
cardElevation | double | 2.0 | – | Card elevation |
showPlayButton | bool | true | – | Play icon overlay |
showLabel | bool | true | – | Show label text |
labelStyle | TextStyle? | null | – | Label fontSize , fontWeight , fontFamily |
labelColor | Color? | null | – | Label color override |
showOverlay | bool | true | – | Bottom overlay visibility |
spacing | double | 6.0 | – | Space between cards |
borderColor | Color? | null | – | Card border color |
borderWidth | int | 0 | – | Card border width |
storyViewedBorderColor | Color? | null | – | Border color when viewed |
numberOfColumns | int? | null | – | Grid columns (grid mode only) |
cardSize | double? | null | – | Fixed size; grid=list height, list=width |
horizontalMargin | double | 0.0 | – | Outer horizontal margin |
horizontalPadding | double | 0.0 | – | Inner horizontal padding |
animationType | CardAnimationType | none | none , pulse | First card animation |
fontName | String? | null | – | Platform font override |
labelFontSize | double? | null | – | Label font size override |
maxStories | int? | null | – | Max items (−1 for all) |
customParameters | Map<String, String>? | null | – | Audience targeting params |
reorderedReadStories | bool? | null | – | Move read stories |
playerBackgroundColor | Color? | null | – | Player background color |
playerVerticalAnchor | String? | null | top , center , bottom | Player vertical alignment |
playerHorizontalMargins | double? | null | – | Player horizontal margins |
playerCornerRadius | double? | null | – | Player corner radius |
playerProgressBarDefaultColor | Color? | null | – | Progress bar base color |
playerProgressBarFillColor | Color? | null | – | Progress bar fill color |
playerProgressBarThickness | double? | null | – | Progress bar thickness |
playerProgressBarRadius | double? | null | – | Progress bar corner radius |
playerStandaloneAnimationOrigin | String? | null | top , topLeft , topRight , bottom , bottomLeft , bottomRight | Standalone open animation origin |
Example
// Card List
CardListWidget(
alias: 'widget-alias',
configuration: const CardConfiguration(
showLabel: true,
labelColor: Color(0xFF8E44AD),
labelFontSize: 16,
fontName: 'Avenir',
showPlayButton: true,
cardElevation: 4,
cardRadius: 12,
showOverlay: true,
spacing: 12,
borderWidth: 2,
borderColor: Color(0xFF9B59B6),
storyViewedBorderColor: Color(0xFFE67E22),
animationType: CardAnimationType.pulse,
reorderedReadStories: false,
maxStories: 3,
// Optional player styling when launching from the card
playerBackgroundColor: Color(0xFF8E44AD),
playerVerticalAnchor: 'bottom',
playerHorizontalMargins: 15.0,
playerCornerRadius: 8.0,
playerProgressBarDefaultColor: Color(0xFF95A5A6),
playerProgressBarFillColor: Color(0xFFE74C3C),
playerProgressBarThickness: 3.0,
playerProgressBarRadius: 6.0,
playerStandaloneAnimationOrigin: 'bottomRight',
),
// same callbacks as BubbleWidget (triggers, player, links, analytics)
);
// Grid Card
CardGridWidget(
alias: 'widget-alias',
configuration: const CardConfiguration(
showLabel: true,
labelColor: Color(0xFF27AE60),
labelFontSize: 18,
fontName: 'Avenir',
showPlayButton: true,
cardElevation: 6,
cardRadius: 16,
showOverlay: true,
spacing: 16,
numberOfColumns: 2,
cardSize: 150,
borderWidth: 3,
borderColor: Color(0xFF2ECC71),
storyViewedBorderColor: Color(0xFFF39C12),
animationType: CardAnimationType.pulse,
reorderedReadStories: true,
maxStories: 5,
),
);
Standalone player
Configuration
Parameter | Type | Default | Allowed values | Description |
---|---|---|---|---|
alias | String | – | – | Widget alias to load |
standaloneOrigin | String? | null | top , topLeft , topRight , bottom , bottomLeft , bottomRight | Open animation origin |
playerBackgroundColor | int? | null | – | ARGB background color |
playerVerticalAnchor | String? | null | top , center , bottom | Vertical alignment |
playerHorizontalMargins | double? | null | – | Horizontal margins |
playerCornerRadius | double? | null | – | Corner radius |
playerProgressBarDefaultColor | int? | null | – | Progress bar base color (ARGB) |
playerProgressBarFillColor | int? | null | – | Progress bar fill color (ARGB) |
playerProgressBarThickness | double? | null | – | Progress bar thickness |
playerProgressBarRadius | double? | null | – | Progress bar corner radius |
-
Optional callbacks are also supported on
JOINStories.startPlayer(...)
(e.g.,onPlayerLoaded
,onPlayerDismissed
, analytics and ecommerce callbacks), but they are event hooks rather than visual customizations. -
Provided complete customization tables for
BubbleWidget
,CardWidget
, and the standalone player, with types, defaults, and allowed values.
Example
await JOINStories.startPlayer(
'widget-alias',
standaloneOrigin: 'top', // 'top'|'topLeft'|'topRight'|'bottom'|'bottomLeft'|'bottomRight'
playerBackgroundColor: 0xFF2C3E50,
playerVerticalAnchor: 'center',
playerHorizontalMargins: 20.0,
playerCornerRadius: 12.0,
playerProgressBarDefaultColor: 0xFF7F8C8D,
playerProgressBarFillColor: 0xFF3498DB,
playerProgressBarThickness: 4.0,
playerProgressBarRadius: 8.0,
onPlayerFetchSuccess: () {},
onPlayerLoaded: () {},
onPlayerFetchError: (msg) {},
onPlayerDismissed: (type) {}, // 'auto' | 'manual'
onContentLinkClick: (link) {},
onAnalyticsEvent: (eventName, payload) {},
);
Custom Fonts
JOIN widgets (Bubble/Card) are native views. To ensure a custom font applies inside those native views, make it available both to Flutter and the native side.
Flutter steps (standard UI)
- Add .ttf/.otf files under assets/fonts/.
- Declare them in pubspec.yaml (family = name used by Flutter UI):
flutter:
uses-material-design: true
fonts:
- family: Parisienne
fonts:
- asset: assets/fonts/Parisienne-Regular.ttf
- Optional: apply globally in your Flutter app:
MaterialApp(
theme: ThemeData(fontFamily: 'Parisienne'),
)
iOS (required for JOIN widgets)
- Copy the font into your iOS project, e.g.
ios/Runner/Fonts/Parisienne-Regular.ttf
(ensure Target Membership to Runner). - Add it to
ios/Runner/Info.plist
:
<key>UIAppFonts</key>
<array>
<string>Fonts/Parisienne-Regular.ttf</string>
<!-- add other variants if needed -->
</array>
- Use the exact PostScript name in the JOIN configurations (
fontName
), for example:
BubbleWidget(
alias: '...',
configuration: const BubbleConfiguration(
fontName: 'Parisienne-Regular',
),
)
CardListWidget(
alias: '...',
configuration: const CardConfiguration(
fontName: 'Parisienne-Regular',
),
)
Notes:
- If the font doesn’t apply, verify the PostScript name (e.g. with macOS Font Book) and cold restart the app.
Android
- Either:
- a) Put the font under
android/app/src/main/res/font/
(e.g.parisienne_regular.ttf
), optionally define ares/font/\*.xml
family. - b) Keep the font in Flutter assets (
assets/fonts/...
). The Android bridge attempts to load fromflutter_assets/...
andassets/fonts/...
and falls back to res/font or a system font.
- a) Put the font under
- For JOIN, pass the same
fontName
as iOS (e.g.'Parisienne-Regular'
).
Best practices:
- Only add variants you actually use (Regular/Bold/Italic). fontName selects a specific variant; there’s no automatic weight/style mapping.
- Always cold restart after adding/modifying fonts.
Updated 7 days ago