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

Command palette (Alfred/Zed style) for Flutter apps.

example/lib/main.dart

import 'package:command_palette_kit/command_palette_kit.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

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

const demoCommands = <CommandModel>[
  CommandModel(
    id: 'navigate:dashboard',
    title: 'Open Dashboard',
    description: 'Show the main dashboard',
    category: 'navigation',
    keywords: ['home', 'main', 'dashboard'],
    shortcut: 'Cmd+D',
    action: CommandActionModel(type: 'navigate', route: '/dashboard'),
  ),
  CommandModel(
    id: 'navigate:settings',
    title: 'Open Settings',
    description: 'Configure the demo app',
    category: 'navigation',
    keywords: ['settings', 'preferences'],
    shortcut: 'Cmd+,',
    action: CommandActionModel(type: 'navigate', route: '/settings'),
  ),
  CommandModel(
    id: 'theme:light',
    title: 'Use Light Theme',
    description: 'Switch the example to the light color scheme',
    category: 'theme',
    keywords: ['light', 'theme'],
    action: CommandActionModel(type: 'theme', params: {'theme': 'light'}),
  ),
  CommandModel(
    id: 'theme:dark',
    title: 'Use Dark Theme',
    description: 'Switch the example to the dark color scheme',
    category: 'theme',
    keywords: ['dark', 'theme'],
    action: CommandActionModel(type: 'theme', params: {'theme': 'dark'}),
  ),
  CommandModel(
    id: 'debug:snackbar',
    title: 'Show Snackbar',
    description: 'Run a custom command handled by the executor',
    category: 'general',
    keywords: ['snackbar', 'message', 'debug'],
    action: CommandActionModel(type: 'custom', params: {'message': 'Hello'}),
  ),
];

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

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

class _ExampleAppState extends State<ExampleApp> {
  ThemeMode _themeMode = ThemeMode.system;
  String _lastAction = 'No command executed yet';

  void _setThemeMode(ThemeMode themeMode) {
    setState(() {
      _themeMode = themeMode;
    });
  }

  void _setLastAction(String value) {
    setState(() {
      _lastAction = value;
    });
  }

  @override
  Widget build(BuildContext context) {
    final repository = CommandRepositoryImpl(
      const InMemoryCommandDataSource(demoCommands),
    );

    return MaterialApp(
      title: 'Command Palette Example',
      theme: ThemeData(colorSchemeSeed: Colors.indigo, useMaterial3: true),
      darkTheme: ThemeData(
        colorSchemeSeed: Colors.indigo,
        brightness: Brightness.dark,
        useMaterial3: true,
      ),
      themeMode: _themeMode,
      home: BlocProvider(
        create: (_) => CommandPaletteBloc(
          getCommands: GetCommands(repository),
          searchCommands: SearchCommands(repository),
        )..add(const LoadCommandsEvent()),
        child: ExampleHomePage(
          lastAction: _lastAction,
          commandExecutor: DemoCommandExecutor(
            onThemeModeChanged: _setThemeMode,
            onActionExecuted: _setLastAction,
          ),
        ),
      ),
    );
  }
}

class ExampleHomePage extends StatelessWidget {
  const ExampleHomePage({
    required this.lastAction,
    required this.commandExecutor,
    super.key,
  });

  final String lastAction;
  final CommandActionExecutor commandExecutor;

  @override
  Widget build(BuildContext context) {
    return CommandPaletteOverlay(
      commandExecutor: commandExecutor,
      quickActions: [
        QuickAction.search(
          onTap: () {
            context.read<CommandPaletteBloc>().add(
                  const ShowCommandPaletteEvent(),
                );
          },
        ),
        QuickAction.newNote(
          onTap: () {
            ScaffoldMessenger.of(context).showSnackBar(
              const SnackBar(content: Text('New note quick action')),
            );
          },
        ),
      ],
      child: Scaffold(
        appBar: AppBar(title: const Text('Command Palette Example')),
        body: Padding(
          padding: const EdgeInsets.all(24),
          child: Center(
            child: ConstrainedBox(
              constraints: const BoxConstraints(maxWidth: 640),
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                crossAxisAlignment: CrossAxisAlignment.stretch,
                children: [
                  Text(
                    'Press Cmd+K or Ctrl+K to open the palette.',
                    style: Theme.of(context).textTheme.titleLarge,
                    textAlign: TextAlign.center,
                  ),
                  const SizedBox(height: 16),
                  Text(
                    lastAction,
                    textAlign: TextAlign.center,
                  ),
                  const SizedBox(height: 24),
                  Align(
                    child: FilledButton.icon(
                      onPressed: () {
                        context.read<CommandPaletteBloc>().add(
                              const ShowCommandPaletteEvent(),
                            );
                      },
                      icon: const Icon(Icons.keyboard_command_key),
                      label: const Text('Open command palette'),
                    ),
                  ),
                ],
              ),
            ),
          ),
        ),
      ),
    );
  }
}

class DemoCommandExecutor implements CommandActionExecutor {
  const DemoCommandExecutor({
    required this.onThemeModeChanged,
    required this.onActionExecuted,
  });

  final ValueChanged<ThemeMode> onThemeModeChanged;
  final ValueChanged<String> onActionExecuted;

  @override
  Future<void> execute(BuildContext context, CommandEntity command) async {
    final theme = command.action.params?['theme'];
    if (theme == 'light') {
      onThemeModeChanged(ThemeMode.light);
    } else if (theme == 'dark') {
      onThemeModeChanged(ThemeMode.dark);
    }

    final message = 'Executed: ${command.title}';
    onActionExecuted(message);
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(content: Text(message)),
    );
  }
}

class InMemoryCommandDataSource implements CommandLocalDataSource {
  const InMemoryCommandDataSource(this.commands);

  final List<CommandModel> commands;

  @override
  Future<List<CommandModel>> getCommands() async => commands;
}
1
likes
160
points
55
downloads

Documentation

API reference

Publisher

verified publisher1telenk0v.space

Weekly Downloads

Command palette (Alfred/Zed style) for Flutter apps.

Homepage

Topics

#command-palette #shortcuts #search #flutter

License

MIT (license)

Dependencies

equatable, flutter, flutter_bloc

More

Packages that depend on command_palette_kit