crowdhandler_flutter 1.0.1 copy "crowdhandler_flutter: ^1.0.1" to clipboard
crowdhandler_flutter: ^1.0.1 copied to clipboard

A Flutter package for integrating CrowdHandler waiting room logic

example/lib/main.dart

import 'package:flutter/material.dart';
// Import your package entry
import 'package:crowdhandler_flutter/crowdhandler_flutter.dart';

/// This example demonstrates how to integrate CrowdHandler in a simple Flutter app.
/// 
/// 1) We create a [CrowdHandlerSession].
/// 2) We call [session.createOrFetch(...)] with a URL that represents the
///    domain/room you configured in CrowdHandler's backend.
/// 3) If the user is not promoted (promoted == 0), we push a waiting room route.
/// 
/// See also the commented sections below (Approaches A/B/C) for more advanced
/// multi-screen usage patterns.
void main() {
  runApp(const CrowdHandlerExampleApp());
}

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

  @override 
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'CrowdHandler Example',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepOrange),
        useMaterial3: true,
      ),

      // If you want to try the RouteObserver approach (Approach B), 
      // uncomment the 'navigatorObservers' line below, then see the 
      // commented code in "APPROACH B" below.
/*
      navigatorObservers: [
        MyCrowdHandlerRouteObserver(
          CrowdHandlerSession(xApiKey: 'YOUR_API_KEY'),
        )
      ],
*/

      // By default, we go to a single "Home" screen that triggers CrowdHandler
      home: const CrowdHandlerHomePage(),
    );
  }
}

/// A simple home page demonstrating how to:
///   1) Create a [CrowdHandlerSession].
///   2) Call [session.createOrFetch(...)] with a typical CrowdHandler URL:
///      e.g., 'https://YOUR_DOMAIN.com/path-to-protected-event'.
///   3) If user is not promoted, show the waiting room route.
class CrowdHandlerHomePage extends StatefulWidget {
  const CrowdHandlerHomePage({super.key});

  @override
  State<CrowdHandlerHomePage> createState() => _CrowdHandlerHomePageState();
}

class _CrowdHandlerHomePageState extends State<CrowdHandlerHomePage> {
  // 1) Create a session-based interface with your xApiKey
  final session = CrowdHandlerSession(
    // Insert your real CrowdHandler API key here.
    // Found in CrowdHandler Control Panel -> Account -> API 
    xApiKey: 'YOUR_PUBLIC_API_KEY',
  );

  CrowdHandlerResult? latestResult;
  bool isLoading = false;
  String errorMessage = '';

  /// Example function that calls [session.createOrFetch(...)] with a
  /// hard-coded URL: 'https://example.com/protected-event-id'.
  /// 
  /// In a real app, you'd dynamically build your URL based on the event or
  /// screen context, e.g. `https://mydomain.com/$myEventID`.
  Future<void> _onCreateOrFetch() async {
    setState(() {
      isLoading = true;
      errorMessage = '';
    });
    try {
      // 2) Attempt to create or fetch a request.
      // Replace 'https://example.com/protected-event-id' with your 
      // own domain & protected event ID, e.g. 'https://mydomain.com/event123'.
      // The domain should match the one that you configured in the CrowdHandler control panel.
      // The event ID should be protected by your CrowdHandler room configuration.
      final result = await session.createOrFetch('https://example.com/protected-event-id');
      setState(() => latestResult = result);

      // 3) If promoted == 0, user needs the waiting room. 
      //    We'll show the minimal approach by default:
      if (result.promoted == 0 && mounted) {
        Navigator.push(
          context,
          WaitingRoomPageRoute(
            // For typical usage, pass result.slug (or your own slug).
            slug: result.slug ?? 'hardcoded-backup-slug-here',
            session: session,
            onPromoted: (newToken) {
              // Optionally do something if we get a new token
              if (newToken != null) {
                ScaffoldMessenger.of(context).showSnackBar(
                  SnackBar(content: Text('Promoted! new token: $newToken')),
                );
              }
            },
            pageTitle: 'Waiting Room', // optional title
          ),
        );

        // -------------
        // ALTERNATIVE: custom UI approach with a direct [WaitingRoomWebView] 
        // instead of the built-in route:
        // -------------
        /*
        Navigator.push(
          context,
          MaterialPageRoute(
            builder: (_) => Scaffold(
              appBar: AppBar(title: const Text('Custom Room')),
              body: WaitingRoomWebView(
                slug: result.slug ?? 'hardcoded-backup-slug-here',
                session: session,
                onPromoted: (newToken) {
                  if (newToken != null) {
                    ScaffoldMessenger.of(context).showSnackBar(
                      SnackBar(content: Text('Custom approach, new token: $newToken')),
                    );
                  }
                },
              ),
            ),
          ),
        );
        */
      }
      // If promoted == 1, user is already in. You can do next steps here.

    } catch (e) {
      setState(() => errorMessage = '$e');
    } finally {
      setState(() => isLoading = false);
    }
  }

  @override
  Widget build(BuildContext context) {
    final resultText = latestResult == null ? 'None' : latestResult.toString();

    return Scaffold(
      appBar: AppBar(
        title: const Text('CrowdHandler Demo'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          children: [
            if (isLoading)
              const LinearProgressIndicator(),

            ElevatedButton(
              onPressed: _onCreateOrFetch,
              child: const Text('Create or Fetch Request'),
            ),

            const SizedBox(height: 20),
            Text('Result: $resultText'),

            if (errorMessage.isNotEmpty) ...[
              const SizedBox(height: 20),
              Text('Error: $errorMessage', style: const TextStyle(color: Colors.red)),
            ],
          ],
        ),
      ),
    );
  }
}

/* ---------------------------------------------------------------------------
 APPROACH A: "Per-Screen initState"
 
 If you have multiple screens, you can call CrowdHandler in each screen's 
 initState, using a dynamic URL. For example, if your app shows 
 "EventDetailPage" for event ID "5305," you'd build a URL like:
 "https://mydomain.com/5305" or "https://test.crowdhandler.com/5305"

class MyScreen extends StatefulWidget {
  const MyScreen({super.key, required this.eventId});
  final String eventId;

  @override
  State<MyScreen> createState() => _MyScreenState();
}

class _MyScreenState extends State<MyScreen> {
  @override
  void initState() {
    super.initState();
    _checkCrowdHandler();
  }

  Future<void> _checkCrowdHandler() async {
    final session = CrowdHandlerSession(xApiKey: 'YOUR_API_KEY');

    // Construct your CrowdHandler URL from eventId:
    // e.g. "https://mydomain.com/${widget.eventId}"
    final result = await session.createOrFetch('https://mydomain.com/${widget.eventId}');
    
    // If user not promoted => show waiting room route:
    if (result.promoted == 0 && mounted) {
      Navigator.push(
        context,
        WaitingRoomPageRoute(slug: result.slug ?? widget.eventId, session: session),
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    return const Scaffold(
      body: Center(child: Text('Hello from MyScreen, checks CrowdHandler in initState')),
    );
  }
}
--------------------------------------------------------------------------- */

/* ---------------------------------------------------------------------------
 APPROACH B: RouteObserver 
 You can watch route transitions with a "CrowdHandlerRouteObserver" 
 that calls session.createOrFetch when a route is pushed.
 
class CrowdHandlerRouteObserver extends RouteObserver<PageRoute<dynamic>> {
  final CrowdHandlerSession session;

  CrowdHandlerRouteObserver(this.session);

  @override
  void didPush(Route route, Route? previousRoute) {
    super.didPush(route, previousRoute);

    // For example, if route.settings.name == '/event/5305',
    // build your URL "https://mydomain.com/5305" and check CrowdHandler:
    if (route.settings.name != null) {
      final slug = route.settings.name!.replaceAll('/event/', '');
      _checkCrowdHandler(slug);
    }
  }

  Future<void> _checkCrowdHandler(String slug) async {
    final result = await session.createOrFetch('https://mydomain.com/$slug');
    if (result.promoted == 0) {
      // Show waiting room
    }
  }
}

// Then in MaterialApp:
MaterialApp(
  navigatorObservers: [
    CrowdHandlerRouteObserver(CrowdHandlerSession(xApiKey: 'YOUR_API_KEY')),
  ],
  // ...
);
--------------------------------------------------------------------------- */

/* ---------------------------------------------------------------------------
 APPROACH C: BaseCrowdHandlerPage 
 For advanced devs who want a base class that auto-checks CrowdHandler 
 in initState for every page that extends it.

abstract class BaseCrowdHandlerPage extends StatefulWidget {
  final String slug;
  const BaseCrowdHandlerPage({Key? key, required this.slug}) : super(key: key);
}

abstract class BaseCrowdHandlerState<T extends BaseCrowdHandlerPage> extends State<T> {
  @override
  void initState() {
    super.initState();
    _checkCrowd(widget.slug);
  }

  Future<void> _checkCrowd(String slug) async {
    final session = CrowdHandlerSession(xApiKey: 'YOUR_API_KEY');
    final result = await session.createOrFetch('https://mydomain.com/$slug');
    if (result.promoted == 0 && mounted) {
      Navigator.push(
        context,
        WaitingRoomPageRoute(slug: slug, session: session),
      );
    }
  }
}

// Then your page extends BaseCrowdHandlerPage:
class MyFancyPage extends BaseCrowdHandlerPage {
  const MyFancyPage({super.key, required super.slug});

  @override
  BaseCrowdHandlerState<BaseCrowdHandlerPage> createState() => _MyFancyPageState();
}

class _MyFancyPageState extends BaseCrowdHandlerState<MyFancyPage> {
  @override
  Widget build(BuildContext context) {
    return const Scaffold(body: Center(child: Text('Fancy Page with auto-check')));
  }
}
--------------------------------------------------------------------------- */
copied to clipboard
2
likes
140
points
173
downloads

Publisher

unverified uploader

Weekly Downloads

2024.08.07 - 2025.02.19

A Flutter package for integrating CrowdHandler waiting room logic

Repository (GitHub)

Documentation

API reference

License

Apache-2.0 (license)

Dependencies

flutter, http, webview_flutter

More

Packages that depend on crowdhandler_flutter