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

On-device AI settings proposals for the app_settings plugin. Apple Foundation Models on iOS, Gemini Nano on Android. Free and MIT licensed.

example/lib/main.dart

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

void main() {
  runApp(const MyApp());
}

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

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final TextEditingController _request =
      TextEditingController(text: "I'm not getting message alerts");

  SettingsAiAvailability? _availability;
  SettingsProposalResult? _result;
  bool _busy = false;
  String? _error;

  @override
  void initState() {
    super.initState();
    _checkAvailability();
  }

  @override
  void dispose() {
    _request.dispose();
    super.dispose();
  }

  Future<void> _checkAvailability() async {
    final availability = await AppSettingsAI.availability();
    if (mounted) setState(() => _availability = availability);
  }

  Future<void> _prepareModel() async {
    setState(() => _busy = true);
    final availability = await AppSettingsAI.prepareModel();
    if (mounted) {
      setState(() {
        _availability = availability;
        _busy = false;
      });
    }
  }

  Future<void> _propose() async {
    setState(() {
      _busy = true;
      _error = null;
      _result = null;
    });
    final result = await AppSettingsAI.proposeSettings(
      request: _request.text,
      context: const {'notificationsEnabled': false},
    );
    if (mounted) {
      setState(() {
        _result = result;
        _busy = false;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('app_settings_ai')),
        body: ListView(
          padding: const EdgeInsets.all(16),
          children: [
            _availabilityCard(),
            const Divider(height: 32),
            TextField(
              controller: _request,
              decoration: const InputDecoration(
                labelText: 'What is wrong?',
                border: OutlineInputBorder(),
              ),
            ),
            const SizedBox(height: 12),
            FilledButton(
              onPressed: _busy ? null : _propose,
              child: const Text('Propose settings'),
            ),
            if (_busy) ...[
              const SizedBox(height: 16),
              const Center(child: CircularProgressIndicator()),
            ],
            if (_error != null) ...[
              const SizedBox(height: 16),
              Text(_error!, style: const TextStyle(color: Colors.red)),
            ],
            ..._proposals(),
          ],
        ),
      ),
    );
  }

  Widget _availabilityCard() {
    final availability = _availability;
    if (availability == null) return const Card(child: ListTile(title: Text('Checking…')));
    return Card(
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          ListTile(
            leading: Icon(
              availability.isAvailable ? Icons.check_circle : Icons.cancel,
              color: availability.isAvailable ? Colors.green : Colors.orange,
            ),
            title: Text(availability.isAvailable ? 'On-device AI ready' : 'Unavailable'),
            subtitle: Text(
              'provider: ${availability.provider.name}'
              '${availability.reason != null ? '\nreason: ${availability.reason!.name}' : ''}'
              '${availability.message != null ? '\n${availability.message}' : ''}',
            ),
          ),
          // Android only: Gemini Nano can be fetched on demand.
          if (availability.canDownload)
            TextButton(
              onPressed: _busy ? null : _prepareModel,
              child: const Text('Download model'),
            ),
        ],
      ),
    );
  }

  List<Widget> _proposals() {
    final result = _result;
    if (result == null) return const [];
    if (!result.isOk) {
      return [
        const SizedBox(height: 16),
        Text(
          'status: ${result.status.name}'
          '${result.unavailableReason != null ? '\nreason: ${result.unavailableReason!.name}' : ''}'
          '${result.errorMessage != null ? '\n${result.errorMessage}' : ''}',
        ),
      ];
    }
    if (result.proposals.isEmpty) {
      return const [SizedBox(height: 16), Text('No relevant settings found.')];
    }
    return [
      const SizedBox(height: 16),
      for (final proposal in result.proposals)
        Card(
          child: ListTile(
            title: Text(proposal.title),
            subtitle: Text(
              '${proposal.rationale}\n'
              '${proposal.setting.name} · ${(proposal.confidence * 100).round()}%',
            ),
            isThreeLine: true,
            trailing: const Icon(Icons.open_in_new),
            // Equivalent to AppSettings.openAppSettings(type: proposal.setting).
            onTap: () => proposal.open(),
          ),
        ),
    ];
  }
}
0
likes
160
points
0
downloads

Documentation

API reference

Publisher

verified publishernupner.com

Weekly Downloads

On-device AI settings proposals for the app_settings plugin. Apple Foundation Models on iOS, Gemini Nano on Android. Free and MIT licensed.

Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

app_settings, flutter

More

Packages that depend on app_settings_ai

Packages that implement app_settings_ai