join_stories_flutter 1.0.0 copy "join_stories_flutter: ^1.0.0" to clipboard
join_stories_flutter: ^1.0.0 copied to clipboard

JOIN Stories Flutter SDK - Monolithic plugin for JOIN Stories

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:join_stories_flutter/join_stories_flutter.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'JOIN Demo',
      theme: ThemeData(primarySwatch: Colors.blue, fontFamily: 'Parisienne'),
      home: const SplashScreen(),
    );
  }
}

class SplashScreen extends StatefulWidget {
  const SplashScreen({super.key});

  @override
  State<SplashScreen> createState() => _SplashScreenState();
}

class _SplashScreenState extends State<SplashScreen> {
  @override
  void initState() {
    super.initState();
    _initSdk();
  }

  Future<void> _initSdk() async {
    try {
      await JOINStories.initialize(teamId: 'join-test-sdk-new');
      await Future.delayed(const Duration(seconds: 2));
      if (mounted) {
        Navigator.of(context).pushReplacement(
          MaterialPageRoute(builder: (_) => const HomeScreen()),
        );
      }
    } catch (e) {
      if (mounted) {
        Navigator.of(context).pushReplacement(
          MaterialPageRoute(builder: (_) => const HomeScreen()),
        );
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    return const Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            CircularProgressIndicator(),
            SizedBox(height: 20),
            Text('Initializing JOIN SDK...'),
          ],
        ),
      ),
    );
  }
}

class HomeScreen extends StatefulWidget {
  const HomeScreen({super.key});

  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  final _bubbleCtrl = BubbleController();
  final _cardListCtrl = CardController();
  final _cardGridCtrl = CardController();
  Future<void> _startPlayer(String alias, {String? standaloneOrigin}) async {
    try {
      await JOINStories.startPlayer(
        alias,
        standaloneOrigin: standaloneOrigin,
        onPlayerFetchSuccess: () => ScaffoldMessenger.of(context).showSnackBar(
          const SnackBar(content: Text('Standalone: Player fetch success')),
        ),
        onPlayerLoaded: () => ScaffoldMessenger.of(context).showSnackBar(
          const SnackBar(content: Text('Standalone: Player started playing')),
        ),
        onPlayerFetchError: (msg) => ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(content: Text('Standalone: Player fetch error: $msg')),
        ),
        onPlayerDismissed: (type) => ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(content: Text('Standalone: Player dismissed ($type)')),
        ),
        onContentLinkClick: (link) =>
            ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(content: Text('Standalone: Link clicked - $link')),
        ),
        onAnalyticsEvent: (eventName, payload) =>
            ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(content: Text('Standalone Analytics: $eventName')),
        ),
        onSeeToCart: () async {
          await JOINStories.dismissPlayer();
          if (mounted) {
            ScaffoldMessenger.of(context).showSnackBar(
              const SnackBar(content: Text('Cart opened (demo simulation)')),
            );
          }
        },
        onShoppingRedirect: (offerId) async {
          await JOINStories.dismissPlayer();
          if (mounted) {
            ScaffoldMessenger.of(context).showSnackBar(
              SnackBar(content: Text('Redirect to product: $offerId (demo)')),
            );
          }
        },
      );
    } catch (e) {
      if (mounted) {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(content: Text('Error starting player: $e')),
        );
      }
    }
  }

  Future<void> _startPlayerWithTheme(String alias, String theme) async {
    try {
      switch (theme) {
        case 'blue':
          await JOINStories.startPlayer(
            alias,
            standaloneOrigin: 'top',
            playerBackgroundColor: 0xFF2C3E50,
            playerVerticalAnchor: 'center',
            playerHorizontalMargins: 20.0,
            playerCornerRadius: 12.0,
            playerProgressBarDefaultColor: 0xFF7F8C8D,
            playerProgressBarFillColor: 0xFF3498DB,
            playerProgressBarThickness: 4.0,
            playerProgressBarRadius: 8.0,
            onPlayerFetchSuccess: () =>
                ScaffoldMessenger.of(context).showSnackBar(
              const SnackBar(content: Text('Standalone: Player fetch success')),
            ),
            onPlayerFetchError: (msg) =>
                ScaffoldMessenger.of(context).showSnackBar(
              SnackBar(content: Text('Standalone: Player fetch error: $msg')),
            ),
          );
          break;
        case 'red':
          await JOINStories.startPlayer(
            alias,
            standaloneOrigin: 'bottomLeft',
            playerBackgroundColor: 0xFFE74C3C,
            playerVerticalAnchor: 'bottom',
            playerHorizontalMargins: 15.0,
            playerCornerRadius: 8.0,
            playerProgressBarDefaultColor: 0xFF95A5A6,
            playerProgressBarFillColor: 0xFFE74C3C,
            playerProgressBarThickness: 3.0,
            playerProgressBarRadius: 6.0,
            onPlayerFetchSuccess: () =>
                ScaffoldMessenger.of(context).showSnackBar(
              const SnackBar(content: Text('Standalone: Player fetch success')),
            ),
            onPlayerFetchError: (msg) =>
                ScaffoldMessenger.of(context).showSnackBar(
              SnackBar(content: Text('Standalone: Player fetch error: $msg')),
            ),
          );
          break;
        case 'green':
          await JOINStories.startPlayer(
            alias,
            standaloneOrigin: 'topRight',
            playerBackgroundColor: 0xFF27AE60,
            playerVerticalAnchor: 'top',
            playerHorizontalMargins: 25.0,
            playerCornerRadius: 15.0,
            playerProgressBarDefaultColor: 0xFFBDC3C7,
            playerProgressBarFillColor: 0xFFF39C12,
            playerProgressBarThickness: 5.0,
            playerProgressBarRadius: 10.0,
            onPlayerFetchSuccess: () =>
                ScaffoldMessenger.of(context).showSnackBar(
              const SnackBar(content: Text('Standalone: Player fetch success')),
            ),
            onPlayerFetchError: (msg) =>
                ScaffoldMessenger.of(context).showSnackBar(
              SnackBar(content: Text('Standalone: Player fetch error: $msg')),
            ),
          );
          break;
      }
    } catch (e) {
      if (mounted) {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(content: Text('Error starting player: $e')),
        );
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('JOIN Stories Flutter Demo'),
        backgroundColor: Colors.blue,
        foregroundColor: Colors.white,
      ),
      body: RefreshIndicator(
        onRefresh: () async {
          await _bubbleCtrl.refresh();
          await _cardListCtrl.refresh();
          await _cardGridCtrl.refresh();
        },
        child: SingleChildScrollView(
          physics: const AlwaysScrollableScrollPhysics(),
          padding: const EdgeInsets.all(16.0),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: [
              const Text(
                'JOIN Stories Widgets',
                style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
              ),
              const SizedBox(height: 16),
              BubbleWidget(
                alias: 'test-sdk-shopping',
                controller: _bubbleCtrl,
                onNativeViewCreated: (id) => _bubbleCtrl.attach(id),
                configuration: const BubbleConfiguration(
                  showLabel: true,
                  labelColor: Color(0xFF2C3E50),
                  labelFontSize: 14,
                  fontName: 'Parisienne-Regular',
                  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,
                  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",
                ),
                onTriggerFetchSuccess: (itemCount) {
                  print(
                      '🎉 Bubble: Trigger fetch success with $itemCount items');
                  ScaffoldMessenger.of(context).showSnackBar(
                    SnackBar(
                        content: Text('Bubble: Loaded $itemCount stories')),
                  );
                },
                onTriggerFetchEmpty: () {
                  print('⚠️ Bubble: No stories available');
                  ScaffoldMessenger.of(context).showSnackBar(
                    const SnackBar(
                        content: Text('Bubble: No stories available')),
                  );
                },
                onTriggerFetchError: (error) {
                  print('❌ Bubble: Trigger fetch error: $error');
                  ScaffoldMessenger.of(context).showSnackBar(
                    SnackBar(content: Text('Bubble Error: $error')),
                  );
                },
                onPlayerLoaded: () {
                  print('▶️ Bubble: Player loaded and playing');
                  ScaffoldMessenger.of(context).showSnackBar(
                    const SnackBar(
                        content: Text('Bubble: Player started playing')),
                  );
                },
                onPlayerDismissed: (type) {
                  print('🔚 Bubble: Player dismissed ($type)');
                  ScaffoldMessenger.of(context).showSnackBar(
                    SnackBar(content: Text('Bubble: Player dismissed ($type)')),
                  );
                },
                onContentLinkClick: (link) {
                  print('🔗 Bubble: Content link clicked: $link');
                  ScaffoldMessenger.of(context).showSnackBar(
                    SnackBar(content: Text('Bubble: Link clicked - $link')),
                  );
                },
                onAnalyticsEvent: (eventName, payload) {
                  print('📊 Bubble Analytics: $eventName - $payload');
                  ScaffoldMessenger.of(context).showSnackBar(
                    SnackBar(content: Text('Bubble Analytics: $eventName')),
                  );
                },
                onSeeToCart: () async {
                  await JOINStories.dismissPlayer();
                  if (mounted) {
                    ScaffoldMessenger.of(context).showSnackBar(
                      const SnackBar(content: Text('Cart opened (demo simulation)')),
                    );
                  }
                },
                onShoppingRedirect: (offerId) async {
                  await JOINStories.dismissPlayer();
                  if (mounted) {
                    ScaffoldMessenger.of(context).showSnackBar(
                      SnackBar(content: Text('Redirect to product: $offerId (demo)')),
                    );
                  }
                },
              ),
              const SizedBox(height: 16),
              CardListWidget(
                alias: 'widget-fft',
                onNativeViewCreated: (id) => _cardListCtrl.attach(id),
                configuration: const CardConfiguration(
                  showLabel: true,
                  labelColor: Color(0xFF8E44AD),
                  labelFontSize: 16,
                  fontName: 'DynaPuff-Regular',
                  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,
                  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",
                ),
                onTriggerFetchSuccess: (itemCount) {
                  print(
                      '🎉 CardList: Trigger fetch success with $itemCount items');
                  ScaffoldMessenger.of(context).showSnackBar(
                    SnackBar(
                        content: Text('CardList: Loaded $itemCount stories')),
                  );
                },
                onTriggerFetchEmpty: () {
                  print('⚠️ CardList: No stories available');
                  ScaffoldMessenger.of(context).showSnackBar(
                    const SnackBar(
                        content: Text('CardList: No stories available')),
                  );
                },
                onTriggerFetchError: (error) {
                  print('❌ CardList: Trigger fetch error: $error');
                  ScaffoldMessenger.of(context).showSnackBar(
                    SnackBar(content: Text('CardList Error: $error')),
                  );
                },
                onPlayerLoaded: () {
                  print('▶️ CardList: Player loaded and playing');
                  ScaffoldMessenger.of(context).showSnackBar(
                    const SnackBar(
                        content: Text('CardList: Player started playing')),
                  );
                },
                onPlayerDismissed: (type) {
                  print('🔚 CardList: Player dismissed ($type)');
                  ScaffoldMessenger.of(context).showSnackBar(
                    SnackBar(
                        content: Text('CardList: Player dismissed ($type)')),
                  );
                },
                onContentLinkClick: (link) {
                  print('🔗 CardList: Content link clicked: $link');
                  ScaffoldMessenger.of(context).showSnackBar(
                    SnackBar(content: Text('CardList: Link clicked - $link')),
                  );
                },
                onAnalyticsEvent: (eventName, payload) {
                  print('📊 CardList Analytics: $eventName - $payload');
                  ScaffoldMessenger.of(context).showSnackBar(
                    SnackBar(content: Text('CardList Analytics: $eventName')),
                  );
                },
                onSeeToCart: () async {
                  await JOINStories.dismissPlayer();
                  if (mounted) {
                    ScaffoldMessenger.of(context).showSnackBar(
                      const SnackBar(content: Text('Cart opened (demo simulation)')),
                    );
                  }
                },
                onShoppingRedirect: (offerId) async {
                  await JOINStories.dismissPlayer();
                  if (mounted) {
                    ScaffoldMessenger.of(context).showSnackBar(
                      SnackBar(content: Text('Redirect to product: $offerId (demo)')),
                    );
                  }
                },
              ),
              const SizedBox(height: 16),
              CardGridWidget(
                alias: 'widget-fft',
                onNativeViewCreated: (id) => _cardGridCtrl.attach(id),
                configuration: const CardConfiguration(
                  showLabel: true,
                  labelColor: Color(0xFF27AE60),
                  labelFontSize: 18,
                  fontName: 'Parisienne-Regular',
                  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,
                  playerBackgroundColor: Color(0xFF27AE60),
                  playerVerticalAnchor: "top",
                  playerHorizontalMargins: 25.0,
                  playerCornerRadius: 15.0,
                  playerProgressBarDefaultColor: Color(0xFFBDC3C7),
                  playerProgressBarFillColor: Color(0xFFF39C12),
                  playerProgressBarThickness: 5.0,
                  playerProgressBarRadius: 10.0,
                  playerStandaloneAnimationOrigin: "topLeft",
                ),
              ),
              const Text(
                'Standalone Player Tests',
                style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
              ),
              const SizedBox(height: 16),
              ElevatedButton(
                onPressed: () => _startPlayer('test-sdk-shopping'),
                child: const Text('Open Story (Legacy API)'),
              ),
              const SizedBox(height: 8),
              ElevatedButton(
                onPressed: () =>
                    _startPlayer('test-sdk-shopping', standaloneOrigin: 'top'),
                child: const Text('Standalone Player (top)'),
              ),
              const SizedBox(height: 4),
              ElevatedButton(
                onPressed: () => _startPlayer('test-sdk-shopping',
                    standaloneOrigin: 'bottom'),
                child: const Text('Standalone Player (bottom)'),
              ),
              const SizedBox(height: 4),
              ElevatedButton(
                onPressed: () => _startPlayer('test-sdk-shopping',
                    standaloneOrigin: 'topLeft'),
                child: const Text('Standalone Player (topLeft)'),
              ),
              const SizedBox(height: 4),
              ElevatedButton(
                onPressed: () => _startPlayer('test-sdk-shopping',
                    standaloneOrigin: 'bottomRight'),
                child: const Text('Standalone Player (bottomRight)'),
              ),
              const SizedBox(height: 16),
              const Text(
                'Custom Player Configuration Tests',
                style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
              ),
              const SizedBox(height: 16),
              ElevatedButton(
                onPressed: () =>
                    _startPlayerWithTheme('test-sdk-shopping', 'blue'),
                child: const Text('Custom Player (Blue Theme)'),
              ),
              const SizedBox(height: 4),
              ElevatedButton(
                onPressed: () =>
                    _startPlayerWithTheme('test-sdk-shopping', 'red'),
                child: const Text('Custom Player (Red Theme)'),
              ),
              const SizedBox(height: 4),
              ElevatedButton(
                onPressed: () =>
                    _startPlayerWithTheme('test-sdk-shopping', 'green'),
                child: const Text('Custom Player (Green Theme)'),
              ),
              const SizedBox(height: 16),
              ElevatedButton(
                onPressed: () async {
                  try {
                    await JOINStories.dismissPlayer();
                  } catch (e) {
                    if (mounted) {
                      ScaffoldMessenger.of(context).showSnackBar(
                        SnackBar(content: Text('Error dismissing player: $e')),
                      );
                    }
                  }
                },
                child: const Text('Dismiss Player'),
              ),
              const SizedBox(height: 16),
              const Text(
                'Analytics Tests',
                style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
              ),
              const SizedBox(height: 16),
              ElevatedButton(
                onPressed: () async {
                  try {
                    await JOINStories.setTrackingUserId('user_123');
                    ScaffoldMessenger.of(context).showSnackBar(
                      const SnackBar(
                          content: Text('Tracking User ID set to: user_123')),
                    );
                  } catch (e) {
                    ScaffoldMessenger.of(context).showSnackBar(
                      SnackBar(
                          content: Text('Error setting tracking user ID: $e')),
                    );
                  }
                },
                child: const Text('Set Tracking User ID'),
              ),
              const SizedBox(height: 8),
              ElevatedButton(
                onPressed: () async {
                  try {
                    await JOINStories.sendConversion('purchase', 'ecommerce');
                    ScaffoldMessenger.of(context).showSnackBar(
                      const SnackBar(
                          content:
                              Text('Conversion sent: purchase (ecommerce)')),
                    );
                  } catch (e) {
                    ScaffoldMessenger.of(context).showSnackBar(
                      SnackBar(content: Text('Error sending conversion: $e')),
                    );
                  }
                },
                child: const Text('Send Conversion'),
              ),
              const SizedBox(height: 8),
              ElevatedButton(
                onPressed: () async {
                  try {
                    await JOINStories.setSegmentationKey('premium_user');
                    ScaffoldMessenger.of(context).showSnackBar(
                      const SnackBar(
                          content:
                              Text('Segmentation key set to: premium_user')),
                    );
                  } catch (e) {
                    ScaffoldMessenger.of(context).showSnackBar(
                      SnackBar(
                          content: Text('Error setting segmentation key: $e')),
                    );
                  }
                },
                child: const Text('Set Segmentation Key'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}
0
likes
140
points
136
downloads

Publisher

unverified uploader

Weekly Downloads

JOIN Stories Flutter SDK - Monolithic plugin for JOIN Stories

Homepage

Documentation

API reference

License

MIT (license)

Dependencies

flutter, plugin_platform_interface

More

Packages that depend on join_stories_flutter

Packages that implement join_stories_flutter