update_gate 0.1.0 copy "update_gate: ^0.1.0" to clipboard
update_gate: ^0.1.0 copied to clipboard

Forced and optional app-update prompts for Flutter, independent of where the version rules come from. Fails open, localised in en, fr and ar, RTL ready.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:update_gate/update_gate.dart';

void main() => runApp(const ExampleApp());

/// The version this example pretends to be. A real app reads it from
/// package_info_plus; see the README.
const String runningVersion = '1.2.0+12';

/// Demo scenarios, each backed by a [StaticSource].
enum Scenario {
  /// Below the minimum version.
  forced(UpdatePolicy(
    minRequiredVersion: '1.3.0',
    latestVersion: '1.4.0',
    storeUrl: 'https://example.com/store',
  )),

  /// Above the minimum, below the latest.
  optional(UpdatePolicy(
    minRequiredVersion: '1.0.0',
    latestVersion: '1.4.0',
    storeUrl: 'https://example.com/store',
    remindAfter: Duration(minutes: 1),
    messages: {
      'en': 'Version 1.4 brings offline mode.',
      'fr': 'La version 1.4 apporte le mode hors ligne.',
      'ar': 'يضيف الإصدار 1.4 وضع عدم الاتصال.',
    },
  )),

  /// Up to date.
  upToDate(UpdatePolicy(minRequiredVersion: '1.0.0', latestVersion: '1.2.0')),

  /// Junk data: fails open.
  broken(UpdatePolicy(minRequiredVersion: 'not-a-version'));

  const Scenario(this.policy);

  /// The rules served for this scenario.
  final UpdatePolicy policy;
}

/// The example app.
class ExampleApp extends StatefulWidget {
  /// Creates the example app.
  const ExampleApp({super.key});

  @override
  State<ExampleApp> createState() => _ExampleAppState();
}

class _ExampleAppState extends State<ExampleApp> {
  Scenario _scenario = Scenario.optional;
  Locale _locale = const Locale('en');
  final _remindStore = InMemoryRemindLaterStore();
  final _messengerKey = GlobalKey<ScaffoldMessengerState>();

  void _openStore(UpdateDecision decision) {
    // A real app calls url_launcher here:
    //   launchUrl(decision.storeUrl!, mode: LaunchMode.externalApplication);
    _messengerKey.currentState?.showSnackBar(
      SnackBar(content: Text('Would open ${decision.storeUrl}')),
    );
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      // A new key restarts the app, so the gate checks again.
      key: ValueKey((_scenario, _locale)),
      scaffoldMessengerKey: _messengerKey,
      theme: ThemeData(colorSchemeSeed: Colors.indigo),
      locale: _locale,
      supportedLocales: const [Locale('en'), Locale('fr'), Locale('ar')],
      localizationsDelegates: GlobalMaterialLocalizations.delegates,
      home: UpdateGate(
        source: StaticSource(_scenario.policy),
        currentVersion: () => runningVersion,
        onOpenStore: _openStore,
        remindLaterStore: _remindStore,
        forcedBuilder: (context, prompt) => Stack(
          children: [
            ForcedUpdatePage(prompt: prompt),
            // Only for the demo: a real forced page offers no way out.
            PositionedDirectional(
              top: 40,
              end: 8,
              child: TextButton(
                onPressed: () => setState(() => _scenario = Scenario.optional),
                child: const Text('Demo: leave'),
              ),
            ),
          ],
        ),
        child: DemoHome(
          scenario: _scenario,
          locale: _locale,
          onScenario: (s) => setState(() => _scenario = s),
          onLocale: (l) => setState(() => _locale = l),
        ),
      ),
    );
  }
}

/// Lets you switch scenario and language.
class DemoHome extends StatelessWidget {
  /// Creates the home page.
  const DemoHome({
    super.key,
    required this.scenario,
    required this.locale,
    required this.onScenario,
    required this.onLocale,
  });

  /// The active scenario.
  final Scenario scenario;

  /// The active locale.
  final Locale locale;

  /// Switches scenario.
  final ValueChanged<Scenario> onScenario;

  /// Switches language.
  final ValueChanged<Locale> onLocale;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('update_gate')),
      body: ListView(
        padding: const EdgeInsets.all(16),
        children: [
          const Text('Running version $runningVersion'),
          const SizedBox(height: 16),
          Wrap(
            spacing: 8,
            children: [
              for (final s in Scenario.values)
                ChoiceChip(
                  label: Text(s.name),
                  selected: s == scenario,
                  onSelected: (_) => onScenario(s),
                ),
            ],
          ),
          const Divider(),
          SegmentedButton<String>(
            segments: const [
              ButtonSegment(value: 'en', label: Text('English')),
              ButtonSegment(value: 'fr', label: Text('Français')),
              ButtonSegment(value: 'ar', label: Text('العربية')),
            ],
            selected: {locale.languageCode},
            onSelectionChanged: (s) => onLocale(Locale(s.first)),
          ),
        ],
      ),
    );
  }
}
0
likes
160
points
329
downloads

Documentation

API reference

Publisher

verified publisherabdeldjalilchougui.biz

Weekly Downloads

Forced and optional app-update prompts for Flutter, independent of where the version rules come from. Fails open, localised in en, fr and ar, RTL ready.

Homepage
Repository (GitHub)
View/report issues

Topics

#update #version #force-update #app-update #semver

License

MIT (license)

Dependencies

flutter, http

More

Packages that depend on update_gate