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

A Flutter package for displaying UI components (dialogs, snackbars, toasts, bottom sheets) without BuildContext and managing them by handle or ID.

example/lib/main.dart

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

import 'app_theme.dart';
import 'demo_item.dart';
import 'basic_dialogs.dart';
import 'interactive_dialogs.dart';
import 'snackbars.dart';
import 'bottom_sheets.dart';
import 'toasts.dart';

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

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

  // Global navigator key used by the contextless UI system
  static final navigatorKey = GlobalKey<NavigatorState>();

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Contextless UI',
      theme: AppTheme.light,
      darkTheme: AppTheme.dark,
      themeMode: ThemeMode.system,
      navigatorKey: navigatorKey,
      navigatorObservers: [ContextlessObserver()],
      home: const MyHome(),
      debugShowCheckedModeBanner: false,
    );
  }
}

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

  @override
  State<MyHome> createState() => _MyHomeState();
}

class _MyHomeState extends State<MyHome> {
  final String _lastResult = 'No result yet';
  final int _openDialogCount = 0;

  @override
  void initState() {
    super.initState();
    // No global streams: each component is tracked via handle
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text(
          'Contextless UI',
          style: TextStyle(fontSize: 20, fontWeight: FontWeight.w600),
        ),
      ),
      body: SafeArea(
        child: SingleChildScrollView(
          padding: const EdgeInsets.all(20),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              _buildStatusHeader(),
              const SizedBox(height: 32),

              // Sections
              _buildSection('Basic Dialogs', basicDialogs),
              const SizedBox(height: 24),
              _buildSection('Interactive Dialogs', interactiveDialogs),
              const SizedBox(height: 24),
              _buildSection('Snackbars', snackbarDemos),
              const SizedBox(height: 24),
              _buildSection('Bottom Sheets', bottomSheetDemos),
              const SizedBox(height: 24),
              _buildSection('Toasts', toastDemos),
            ],
          ),
        ),
      ),
    );
  }

  Widget _buildStatusHeader() {
    return Container(
      padding: const EdgeInsets.all(20),
      decoration: BoxDecoration(
        color: Theme.of(context).colorScheme.surfaceContainerHighest,
        borderRadius: BorderRadius.circular(16),
      ),
      child: Row(
        children: [
          Container(
            padding: const EdgeInsets.all(12),
            decoration: BoxDecoration(
              color: _openDialogCount > 0
                  ? Theme.of(context).colorScheme.primary
                  : Theme.of(context).colorScheme.outline,
              borderRadius: BorderRadius.circular(12),
            ),
            child: const Icon(Icons.layers_outlined,
                color: Colors.white, size: 24),
          ),
          const SizedBox(width: 16),
          Expanded(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(
                  '$_openDialogCount Active Dialogs',
                  style: Theme.of(context).textTheme.titleMedium?.copyWith(
                        fontWeight: FontWeight.w600,
                      ),
                ),
                const SizedBox(height: 2),
                Text(
                  _lastResult,
                  style: Theme.of(context).textTheme.bodySmall?.copyWith(
                        color: Theme.of(context).colorScheme.onSurfaceVariant,
                      ),
                ),
              ],
            ),
          ),
          if (_openDialogCount > 0)
            FilledButton(
              onPressed: () => ContextlessUi.closeAllDialogs(),
              style: FilledButton.styleFrom(
                backgroundColor: Theme.of(context).colorScheme.error,
                foregroundColor: Theme.of(context).colorScheme.onError,
                minimumSize: const Size(0, 40),
              ),
              child: const Text('Close All'),
            ),
        ],
      ),
    );
  }

  Widget _buildSection(String title, List<DialogDemo> demos) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Text(
          title,
          style: Theme.of(context).textTheme.headlineSmall?.copyWith(
                fontWeight: FontWeight.w600,
                color: Theme.of(context).colorScheme.onSurface,
              ),
        ),
        const SizedBox(height: 16),
        ...demos.map((demo) => _buildDemoCard(demo)),
      ],
    );
  }

  Widget _buildDemoCard(DialogDemo demo) {
    return Card(
      child: InkWell(
        onTap: demo.onTap,
        borderRadius: BorderRadius.circular(12),
        child: Padding(
          padding: const EdgeInsets.all(20),
          child: Row(
            children: [
              Container(
                padding: const EdgeInsets.all(12),
                decoration: BoxDecoration(
                  color: demo.color.withValues(alpha: 0.1),
                  borderRadius: BorderRadius.circular(12),
                ),
                child: Icon(demo.icon, color: demo.color, size: 24),
              ),
              const SizedBox(width: 16),
              Expanded(
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      demo.title,
                      style: Theme.of(context).textTheme.titleMedium?.copyWith(
                            fontWeight: FontWeight.w500,
                          ),
                    ),
                    const SizedBox(height: 4),
                    Text(
                      demo.description,
                      style: Theme.of(context).textTheme.bodyMedium?.copyWith(
                            color:
                                Theme.of(context).colorScheme.onSurfaceVariant,
                          ),
                    ),
                  ],
                ),
              ),
              Icon(Icons.arrow_forward_ios,
                  size: 16, color: Theme.of(context).colorScheme.outline),
            ],
          ),
        ),
      ),
    );
  }

  // Demo data
}
0
likes
150
points
101
downloads

Publisher

verified publishertegar.site

Weekly Downloads

A Flutter package for displaying UI components (dialogs, snackbars, toasts, bottom sheets) without BuildContext and managing them by handle or ID.

Repository (GitHub)
View/report issues

Documentation

API reference

License

MIT (license)

Dependencies

flutter

More

Packages that depend on contextless_ui