os_intents 0.2.1 copy "os_intents: ^0.2.1" to clipboard
os_intents: ^0.2.1 copied to clipboard

Declare OS-level app actions in Dart. Generates iOS App Intents and Android AppFunctions — no Swift or Kotlin by hand.

example/lib/main.dart

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

import 'intents.dart';
import 'selfcheck.dart';
import 'task_repo.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // $osIntentsRegistry is generated from the annotations in intents.dart.
  // Install it before runApp: an intent can be what launched the app, and the
  // native side buffers that invocation only until this resolves.
  await OsIntents.install($osIntentsRegistry);

  // Answers "what's due today" with no Dart running at all. The app is the only
  // thing that can keep this fresh, since the static path deliberately runs no
  // code of ours — so republish whenever the data changes.
  await _publishDueToday();

  if (selfCheckEnabled) {
    await runSelfCheck(
      registry: $osIntentsRegistry,
      uiSideEffectCount: () => TaskRepo.instance.all.length,
    );
  }

  runApp(const ExampleApp());
}

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

  @override
  Widget build(BuildContext context) => MaterialApp(
    title: 'os_intents example',
    theme: ThemeData(colorSchemeSeed: Colors.indigo),
    home: const TaskListPage(),
  );
}

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

  @override
  State<TaskListPage> createState() => _TaskListPageState();
}

class _TaskListPageState extends State<TaskListPage> {
  @override
  Widget build(BuildContext context) {
    final tasks = TaskRepo.instance.all;
    return Scaffold(
      appBar: AppBar(title: const Text('Tasks')),
      body: tasks.isEmpty
          ? const Center(
              child: Padding(
                padding: EdgeInsets.all(32),
                child: Text(
                  'No tasks yet.\n\n'
                  'Try "Add a task to os_intents example" in Shortcuts, '
                  'or use the button below.',
                  textAlign: TextAlign.center,
                ),
              ),
            )
          : ListView(
              children: [
                for (final t in tasks)
                  CheckboxListTile(
                    value: t.done,
                    title: Text(t.title),
                    subtitle: Text(t.projectName),
                    onChanged: (_) async {
                      await completeTask(taskId: t.id);
                      setState(() {});
                    },
                  ),
              ],
            ),
      floatingActionButton: Column(
        mainAxisSize: MainAxisSize.min,
        crossAxisAlignment: CrossAxisAlignment.end,
        spacing: 12,
        children: [
          // Proves the headless path end to end: this runs addTask in the
          // background engine's isolate, which has its own TaskRepo. The task
          // therefore does NOT appear in the list above — that absence is the
          // evidence a second isolate really ran it.
          FloatingActionButton.extended(
            heroTag: 'bg',
            onPressed: () async {
              final result = await OsIntents.debugInvokeBackground('addTask', {
                'title': 'From the background isolate',
              });
              if (!context.mounted) return;
              ScaffoldMessenger.of(context).showSnackBar(
                SnackBar(content: Text('background engine → $result')),
              );
            },
            icon: const Icon(Icons.bolt),
            label: const Text('Run headless'),
          ),
          FloatingActionButton(
            heroTag: 'fg',
            onPressed: () async {
              // The same function the OS calls — nothing about it is special.
              await addTask(title: 'Task ${TaskRepo.instance.all.length + 1}');
              setState(() {});
            },
            child: const Icon(Icons.add),
          ),
        ],
      ),
    );
  }
}

Future<void> _publishDueToday() async {
  final due = await TaskRepo.instance.dueToday();
  await OsIntents.publishStatic({
    'dueToday': IntentResult.snippet(
      SnippetSpec(
        title: 'Due today',
        subtitle: '${due.length} task(s)',
        rows: [for (final t in due.take(3)) SnippetRow(t.title, t.projectName)],
        imageSystemName: 'calendar',
      ),
      spoken: due.isEmpty
          ? 'Nothing due today'
          : '${due.length} task(s) due today',
    ),
  });
}
1
likes
160
points
272
downloads
screenshot

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Declare OS-level app actions in Dart. Generates iOS App Intents and Android AppFunctions — no Swift or Kotlin by hand.

Repository (GitHub)
View/report issues
Contributing

Topics

#app-intents #siri #shortcuts #assistant #codegen

License

MIT (license)

Dependencies

flutter, meta, os_intents_android, os_intents_ios, os_intents_platform_interface

More

Packages that depend on os_intents