Skip to main content

changelog_flutter_kit 1.1.1 copy "changelog_flutter_kit: ^1.1.1" to clipboard
changelog_flutter_kit: ^1.1.1 copied to clipboard

A headless and platform-adaptive 'What's New' and release notes kit for Flutter apps with native iOS Cupertino, Material 3, SemVer comparison, and persistence.

example/lib/main.dart

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

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(const WhatsNewDemoApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "What's New Showcase",
      theme: ThemeData(
        useMaterial3: true,
        colorSchemeSeed: Colors.indigo,
        brightness: Brightness.light,
      ),
      darkTheme: ThemeData(
        useMaterial3: true,
        colorSchemeSeed: Colors.indigo,
        brightness: Brightness.dark,
      ),
      home: const DemoHomePage(),
    );
  }
}

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

  @override
  State<DemoHomePage> createState() => _DemoHomePageState();
}

class _DemoHomePageState extends State<DemoHomePage> {
  late final InMemoryWhatsNewStorage _storage;
  late final WhatsNewController _controller;
  String _simulatedVersion = '2.1.0';

  final List<VersionChangelog> _sampleChangelogs = [
    const VersionChangelog(
      version: '2.1.0',
      title: 'Performance & Polish',
      releaseDate: 'October 2026',
      entries: [
        ChangelogEntry(
          type: ChangeType.feature,
          title: 'Adaptive Cupertino & Material UI',
          text:
              'Sheets now seamlessly match iOS HIG and Android Material 3 specs.',
          iconOverride: Icons.auto_awesome,
        ),
        ChangelogEntry(
          type: ChangeType.feature,
          title: 'Headless Mode',
          text:
              'Full headless widgets and controller for custom-designed release notes.',
          iconOverride: Icons.developer_mode,
        ),
        ChangelogEntry(
          type: ChangeType.pro,
          title: 'Cloud Realtime Sync',
          text:
              'Sync release settings and announcements across all user devices.',
          isPro: true,
          iconOverride: Icons.cloud_sync_rounded,
        ),
        ChangelogEntry(
          type: ChangeType.improvement,
          title: 'SemVer 2.0 Comparator',
          text: 'Proper precedence logic for prerelease and build tags.',
          iconOverride: Icons.speed_rounded,
        ),
        ChangelogEntry(
          type: ChangeType.fix,
          title: 'Memory Optimization',
          text: 'Eliminated unnecessary rebuilds in sheet list views.',
          iconOverride: Icons.bug_report_rounded,
        ),
      ],
    ),
    const VersionChangelog(
      version: '2.0.0',
      title: 'Major 2.0 Redesign',
      releaseDate: 'September 2026',
      entries: [
        ChangelogEntry(
          type: ChangeType.feature,
          title: 'All-new Design Language',
          text:
              'Polished layouts, dark mode optimization, and micro-interactions.',
          iconOverride: Icons.palette_outlined,
        ),
        ChangelogEntry(
          type: ChangeType.breaking,
          title: 'Updated Controller API',
          text: 'Async storage provider replaced legacy synchronous calls.',
          iconOverride: Icons.warning_amber_rounded,
        ),
      ],
    ),
    const VersionChangelog(
      version: '1.0.0',
      title: 'Initial Release',
      releaseDate: 'January 2026',
      entries: [
        ChangelogEntry(
          type: ChangeType.feature,
          title: 'Welcome to the App',
          text: 'First public version with changelog sheet support.',
          iconOverride: Icons.rocket_launch_rounded,
        ),
      ],
    ),
  ];

  @override
  void initState() {
    super.initState();
    _storage = InMemoryWhatsNewStorage(initialLastSeen: '2.0.0');
    _initController();
  }

  void _initController() {
    _controller = WhatsNewController(
      changelogs: _sampleChangelogs,
      storage: _storage,
      currentVersionProvider: () async => _simulatedVersion,
    );
  }

  void _showPaywallModal(ChangelogEntry entry) {
    showModalBottomSheet<void>(
      context: context,
      builder: (ctx) => Container(
        padding: const EdgeInsets.all(24),
        child: Column(
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            const Icon(Icons.workspace_premium, size: 48, color: Colors.amber),
            const SizedBox(height: 12),
            Text(
              'Unlock ${entry.title ?? "Pro Feature"}',
              style: Theme.of(ctx).textTheme.headlineSmall?.copyWith(
                    fontWeight: FontWeight.bold,
                  ),
              textAlign: TextAlign.center,
            ),
            const SizedBox(height: 8),
            Text(
              entry.text,
              textAlign: TextAlign.center,
              style: Theme.of(ctx).textTheme.bodyMedium,
            ),
            const SizedBox(height: 20),
            FilledButton(
              onPressed: () => Navigator.pop(ctx),
              child: const Text(r'Upgrade to Pro ($4.99/mo)'),
            ),
          ],
        ),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("What's New Showcase"),
        actions: [
          IconButton(
            tooltip: 'View Full History',
            icon: const Icon(Icons.history_rounded),
            onPressed: () {
              WhatsNewSheet.showHistory(
                context,
                changelogs: _sampleChangelogs,
                isProUser: false,
                onProTap: _showPaywallModal,
              );
            },
          ),
        ],
      ),
      body: ListView(
        padding: const EdgeInsets.all(20),
        children: [
          // -----------------------------------------------------------------
          // Headless Embedded Showcase
          // -----------------------------------------------------------------
          Text(
            'HEADLESS MODE (WhatsNewBuilder)',
            style: Theme.of(context).textTheme.labelLarge?.copyWith(
                  letterSpacing: 1.1,
                  fontWeight: FontWeight.bold,
                  color: Theme.of(context).colorScheme.primary,
                ),
          ),
          const SizedBox(height: 8),
          WhatsNewBuilder(
            controller: _controller,
            builder: (context, state) {
              if (state.isLoading) {
                return const Card(
                  child: Padding(
                    padding: EdgeInsets.all(16),
                    child: Center(child: CircularProgressIndicator()),
                  ),
                );
              }

              if (!state.hasUpdate) {
                return Card(
                  color: Theme.of(context).colorScheme.surfaceContainerHighest,
                  child: const Padding(
                    padding: EdgeInsets.all(16),
                    child: Row(
                      children: [
                        Icon(Icons.check_circle_outline, color: Colors.green),
                        SizedBox(width: 12),
                        Expanded(
                          child: Text(
                            'All caught up! No unread changelogs for this version.',
                          ),
                        ),
                      ],
                    ),
                  ),
                );
              }

              final changelog = state.currentChangelog!;
              return Card(
                elevation: 3,
                color: Theme.of(context).colorScheme.primaryContainer,
                child: Padding(
                  padding: const EdgeInsets.all(16),
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Row(
                        children: [
                          const Icon(Icons.celebration_rounded,
                              color: Colors.deepPurple),
                          const SizedBox(width: 8),
                          Expanded(
                            child: Text(
                              'Custom UI Banner: v${changelog.version} — ${changelog.title ?? ""}',
                              style:
                                  const TextStyle(fontWeight: FontWeight.bold),
                            ),
                          ),
                          IconButton(
                            icon: const Icon(Icons.close_rounded),
                            onPressed: state.markCurrentSeen,
                          ),
                        ],
                      ),
                      const SizedBox(height: 8),
                      Text(
                        'This entire card is rendered headlessly with developer-defined widgets!',
                        style: Theme.of(context).textTheme.bodySmall,
                      ),
                      const SizedBox(height: 12),
                      OutlinedButton.icon(
                        onPressed: state.markCurrentSeen,
                        icon: const Icon(Icons.done_all_rounded, size: 18),
                        label: const Text('Mark Seen (Headless API)'),
                      ),
                    ],
                  ),
                ),
              );
            },
          ),
          const SizedBox(height: 32),

          // -----------------------------------------------------------------
          // Headful Presentation Options
          // -----------------------------------------------------------------
          Text(
            'HEADFUL PRESENTATIONS',
            style: Theme.of(context).textTheme.labelLarge?.copyWith(
                  letterSpacing: 1.1,
                  fontWeight: FontWeight.bold,
                  color: Theme.of(context).colorScheme.primary,
                ),
          ),
          const SizedBox(height: 12),

          // iOS Cupertino Style
          Card(
            child: ListTile(
              leading: const CircleAvatar(
                backgroundColor: Colors.blueAccent,
                child: Icon(Icons.phone_iphone_rounded, color: Colors.white),
              ),
              title: const Text('iOS Cupertino Sheet'),
              subtitle: const Text(
                  'Cupertino typography, badges, and action buttons'),
              trailing: const Icon(Icons.arrow_forward_ios_rounded, size: 16),
              onTap: () {
                WhatsNewSheet.show(
                  context,
                  changelog: _sampleChangelogs.first,
                  onGotIt: () async {},
                  isProUser: false,
                  onProTap: _showPaywallModal,
                  presentationStyle: WhatsNewPresentationStyle.cupertino,
                );
              },
            ),
          ),

          // Android Material 3 Style
          Card(
            child: ListTile(
              leading: const CircleAvatar(
                backgroundColor: Colors.teal,
                child: Icon(Icons.android_rounded, color: Colors.white),
              ),
              title: const Text('Android Material 3 Sheet'),
              subtitle:
                  const Text('M3 surface elevation, pills, and FilledButton'),
              trailing: const Icon(Icons.arrow_forward_ios_rounded, size: 16),
              onTap: () {
                WhatsNewSheet.show(
                  context,
                  changelog: _sampleChangelogs.first,
                  onGotIt: () async {},
                  isProUser: false,
                  onProTap: _showPaywallModal,
                  presentationStyle: WhatsNewPresentationStyle.material,
                );
              },
            ),
          ),

          // Dialog Style
          Card(
            child: ListTile(
              leading: const CircleAvatar(
                backgroundColor: Colors.purple,
                child: Icon(Icons.desktop_mac_rounded, color: Colors.white),
              ),
              title: const Text('Centered Modal Dialog'),
              subtitle:
                  const Text('Ideal for Desktop, Web, and Tablet layouts'),
              trailing: const Icon(Icons.arrow_forward_ios_rounded, size: 16),
              onTap: () {
                WhatsNewSheet.show(
                  context,
                  changelog: _sampleChangelogs.first,
                  onGotIt: () async {},
                  isProUser: true,
                  presentationStyle: WhatsNewPresentationStyle.dialog,
                );
              },
            ),
          ),

          // Full History
          Card(
            child: ListTile(
              leading: const CircleAvatar(
                backgroundColor: Colors.deepOrange,
                child: Icon(Icons.library_books_rounded, color: Colors.white),
              ),
              title: const Text('Version History Page'),
              subtitle:
                  const Text('Full scrollable changelog archive for Settings'),
              trailing: const Icon(Icons.arrow_forward_ios_rounded, size: 16),
              onTap: () {
                WhatsNewSheet.showHistory(
                  context,
                  changelogs: _sampleChangelogs,
                  isProUser: false,
                  onProTap: _showPaywallModal,
                );
              },
            ),
          ),

          const SizedBox(height: 32),

          // -----------------------------------------------------------------
          // Simulator & Debug Tools
          // -----------------------------------------------------------------
          Text(
            'TESTING & SIMULATION',
            style: Theme.of(context).textTheme.labelLarge?.copyWith(
                  letterSpacing: 1.1,
                  fontWeight: FontWeight.bold,
                  color: Theme.of(context).colorScheme.primary,
                ),
          ),
          const SizedBox(height: 12),
          FilledButton.tonalIcon(
            onPressed: () async {
              final messenger = ScaffoldMessenger.of(context);
              await _storage.clear();
              if (!mounted) return;
              setState(() {
                _simulatedVersion = '2.1.0';
                _initController();
              });
              messenger.showSnackBar(
                const SnackBar(
                  content: Text('Reset seen state to fresh install!'),
                ),
              );
            },
            icon: const Icon(Icons.restart_alt_rounded),
            label: const Text('Reset Storage (Simulate Fresh Install)'),
          ),
        ],
      ),
    );
  }
}
2
likes
160
points
417
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

A headless and platform-adaptive 'What's New' and release notes kit for Flutter apps with native iOS Cupertino, Material 3, SemVer comparison, and persistence.

Repository (GitHub)
View/report issues

Topics

#changelog #release-notes #whats-new #bottom-sheet #cupertino

License

MIT (license)

Dependencies

flutter, package_info_plus, shared_preferences

More

Packages that depend on changelog_flutter_kit