zerosettle 0.3.4 copy "zerosettle: ^0.3.4" to clipboard
zerosettle: ^0.3.4 copied to clipboard

ZeroSettle SDK for Flutter — Merchant of Record web checkout.

example/lib/main.dart

import 'dart:async';

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

import 'app_state.dart';
import 'iap_environment.dart';
import 'screens/home_screen.dart';
import 'screens/store_screen.dart';
import 'screens/entitlements_screen.dart';
import 'screens/settings_screen.dart';

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'ZeroSettle',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        colorSchemeSeed: Colors.indigo,
        useMaterial3: true,
        brightness: Brightness.light,
      ),
      darkTheme: ThemeData(
        colorSchemeSeed: Colors.indigo,
        useMaterial3: true,
        brightness: Brightness.dark,
      ),
      home: const AppShell(),
    );
  }
}

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

  @override
  State<AppShell> createState() => _AppShellState();
}

class _AppShellState extends State<AppShell> {
  final _appState = AppState();
  late final IAPEnvironmentNotifier _envNotifier;
  int _currentTab = 0;
  StreamSubscription<List<Entitlement>>? _entitlementSub;
  bool _envLoaded = false;

  @override
  void initState() {
    super.initState();
    _envNotifier = IAPEnvironmentNotifier(IAPEnvironment.sandbox);
    _loadEnvironmentAndBoot();
  }

  @override
  void dispose() {
    _entitlementSub?.cancel();
    _envNotifier.dispose();
    super.dispose();
  }

  Future<void> _loadEnvironmentAndBoot() async {
    final env = await IAPEnvironment.load();
    _envNotifier.value = env;
    setState(() => _envLoaded = true);
    await _configureAndBootstrap(env);
  }

  Future<void> _configureAndBootstrap(IAPEnvironment env) async {
    _appState.setLoading(true);
    _appState.setError(null);

    try {
      // 1. Set base URL override (before configure)
      await ZeroSettle.instance.setBaseUrlOverride(env.baseUrlOverride);

      // 2. Configure
      await ZeroSettle.instance.configure(publishableKey: env.publishableKey);

      // 3. Listen to entitlement updates
      _entitlementSub?.cancel();
      _entitlementSub =
          ZeroSettle.instance.entitlementUpdates.listen((entitlements) {
        _appState.setEntitlements(entitlements);
      });

      // 4. Bootstrap
      final catalog =
          await ZeroSettle.instance.bootstrap(userId: _appState.userId);
      _appState.setProducts(catalog.products);
      _appState.setRemoteConfig(catalog.config);
      _appState.setInitialized(true);

      // 5. Restore entitlements
      try {
        final entitlements = await ZeroSettle.instance
            .restoreEntitlements(userId: _appState.userId);
        _appState.setEntitlements(entitlements);
      } catch (_) {
        // Non-fatal: entitlements may be empty for new users
      }
    } on ZSException catch (e) {
      _appState.setError(e.message);
    } finally {
      _appState.setLoading(false);
    }
  }

  Future<void> _switchEnvironment(IAPEnvironment env) async {
    await _envNotifier.switchTo(env);
    _appState.setInitialized(false);
    _appState.setProducts([]);
    _appState.setEntitlements([]);
    await _configureAndBootstrap(env);
  }

  @override
  Widget build(BuildContext context) {
    if (!_envLoaded) {
      return _buildLoadingScreen(context);
    }

    return ListenableBuilder(
      listenable: _appState,
      builder: (context, _) {
        if (!_appState.isInitialized && _appState.isLoading) {
          return _buildLoadingScreen(context);
        }

        return Scaffold(
          body: IndexedStack(
            index: _currentTab,
            children: [
              HomeScreen(
                appState: _appState,
                onNavigateToStore: () => setState(() => _currentTab = 1),
              ),
              StoreScreen(appState: _appState),
              EntitlementsScreen(appState: _appState),
              SettingsScreen(
                appState: _appState,
                envNotifier: _envNotifier,
                onSwitchEnvironment: _switchEnvironment,
              ),
            ],
          ),
          bottomNavigationBar: NavigationBar(
            selectedIndex: _currentTab,
            onDestinationSelected: (index) =>
                setState(() => _currentTab = index),
            destinations: const [
              NavigationDestination(
                icon: Icon(Icons.home_outlined),
                selectedIcon: Icon(Icons.home),
                label: 'Home',
              ),
              NavigationDestination(
                icon: Icon(Icons.store_outlined),
                selectedIcon: Icon(Icons.store),
                label: 'Store',
              ),
              NavigationDestination(
                icon: Icon(Icons.verified_outlined),
                selectedIcon: Icon(Icons.verified),
                label: 'Entitlements',
              ),
              NavigationDestination(
                icon: Icon(Icons.settings_outlined),
                selectedIcon: Icon(Icons.settings),
                label: 'Settings',
              ),
            ],
          ),
        );
      },
    );
  }

  Widget _buildLoadingScreen(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: Theme.of(context),
      home: Scaffold(
        body: Center(
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              Container(
                width: 72,
                height: 72,
                decoration: const BoxDecoration(
                  gradient: LinearGradient(
                    colors: [Colors.indigo, Colors.purple],
                    begin: Alignment.topLeft,
                    end: Alignment.bottomRight,
                  ),
                  shape: BoxShape.circle,
                ),
                child:
                    const Icon(Icons.diamond, size: 32, color: Colors.white),
              ),
              const SizedBox(height: 24),
              Text(
                'ZeroSettle',
                style: Theme.of(context)
                    .textTheme
                    .headlineMedium
                    ?.copyWith(fontWeight: FontWeight.bold),
              ),
              const SizedBox(height: 24),
              const CircularProgressIndicator(),
              const SizedBox(height: 16),
              Text(
                'Initializing...',
                style: Theme.of(context).textTheme.bodyMedium?.copyWith(
                      color: Theme.of(context).colorScheme.onSurfaceVariant,
                    ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}
2
likes
140
points
104
downloads

Documentation

API reference

Publisher

verified publisherzerosettle.io

Weekly Downloads

ZeroSettle SDK for Flutter — Merchant of Record web checkout.

Homepage
Repository (GitHub)
View/report issues

License

Apache-2.0 (license)

Dependencies

flutter, plugin_platform_interface

More

Packages that depend on zerosettle

Packages that implement zerosettle