flutter_mimir 0.0.1-dev.5 copy "flutter_mimir: ^0.0.1-dev.5" to clipboard
flutter_mimir: ^0.0.1-dev.5 copied to clipboard

Extremely powerful, reactive NoSQL database with typo-tolerant full-text search and declarative queries.

example/lib/main.dart

import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_mimir/flutter_mimir.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // Get the index
  final instance = await Mimir.defaultInstance;
  final index = instance.getIndex('movies');

  // Add all the documents async (do NOT await)
  rootBundle
      .loadString('assets/tmdb_movies.json')
      .then((l) => json.decode(l) as List)
      .then((l) => l.cast<Map<String, dynamic>>())
      .then((l) => index.addDocuments(l));

  // Finally, run our application
  runApp(ProviderScope(
    overrides: [indexProvider.overrideWith((_) => index)],
    child: MaterialApp(
      title: 'Mimir Demo',
      theme: ThemeData.light(useMaterial3: true),
      darkTheme: ThemeData.dark(useMaterial3: true),
      home: const Body(),
    ),
  ));
}

// The providers needed for this example
final indexProvider = Provider<MimirIndex>((_) => throw UnimplementedError());
final queryProvider = StateProvider((_) => '');
final searchProvider = StreamProvider((ref) {
  final index = ref.watch(indexProvider);
  final query = ref.watch(queryProvider);

  // When query is null/empty, all docs will be returned
  return index.searchStream(query: query);
});

class Body extends HookConsumerWidget {
  const Body({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final textController = useTextEditingController();
    final searchResults = ref.watch(searchProvider);

    return Scaffold(
      appBar: AppBar(
        title: const Text('Mimir Demo'),
        actions: [
          IconButton(
            icon: const Icon(Icons.info),
            onPressed: () => showInfoDialog(context),
          ),
        ],
        bottom: PreferredSize(
          preferredSize: const Size.fromHeight(56),
          child: Padding(
            padding: const EdgeInsets.only(left: 8, right: 8, bottom: 8),
            child: TextField(
              controller: textController,
              onChanged: (q) => ref.read(queryProvider.notifier).state = q,
              decoration: InputDecoration(
                contentPadding: EdgeInsets.zero,
                border: const OutlineInputBorder(
                  borderRadius: BorderRadius.all(Radius.circular(100)),
                ),
                prefixIcon: const Icon(Icons.search),
                suffixIcon: IconButton(
                  icon: const Icon(Icons.cancel),
                  onPressed: () {
                    textController.text = '';
                    ref.read(queryProvider.notifier).state = '';
                  },
                ),
              ),
            ),
          ),
        ),
      ),
      body: searchResults.when(
        data: (searchResults) => ListView.builder(
          padding: const EdgeInsets.only(top: 16, bottom: 8),
          itemCount: searchResults.length,
          itemBuilder: (_, index) => MovieCard(movie: searchResults[index]),
        ),
        error: (e, s) => Center(child: Text('Error: $e')),
        loading: () => const Center(
          child: CircularProgressIndicator.adaptive(),
        ),
      ),
    );
  }
}

class MovieCard extends StatelessWidget {
  const MovieCard({super.key, required this.movie});

  final Map<String, dynamic> movie;

  @override
  Widget build(BuildContext context) {
    return Card(
      clipBehavior: Clip.antiAlias,
      margin: const EdgeInsets.only(left: 16, right: 16, bottom: 8),
      child: ConstrainedBox(
        constraints: const BoxConstraints(maxHeight: 100),
        child: Row(children: [
          AspectRatio(
            aspectRatio: 188.0 / 282.0,
            child: Image.network(
              'https://www.themoviedb.org/t/p/w188_and_h282_bestv2${movie['poster_path']}',
              fit: BoxFit.fill,
              errorBuilder: (_, __, ___) => Center(
                child: Icon(
                  Icons.cancel,
                  color: Theme.of(context).colorScheme.error,
                ),
              ),
              loadingBuilder: (_, child, progress) {
                if (progress == null) return child;
                return const Center(
                  child: CircularProgressIndicator.adaptive(),
                );
              },
            ),
          ),
          const SizedBox(width: 8),
          Expanded(
            child: ListTile(
              contentPadding: EdgeInsets.zero,
              title: Text(
                movie['title'],
                maxLines: 1,
                overflow: TextOverflow.ellipsis,
              ),
              subtitle: Text(
                movie['overview'],
                maxLines: 3,
                overflow: TextOverflow.ellipsis,
              ),
            ),
          ),
          const SizedBox(width: 8),
          Text((movie['release_date'] as String).split('-')[0]),
          const SizedBox(width: 12),
        ]),
      ),
    );
  }
}

void showInfoDialog(BuildContext context) {
  showDialog(
    context: context,
    builder: (context) => AlertDialog(
      title: const Text('info'),
      content: const Text('Movie data provided by themoviedb.org.'),
      actions: [
        TextButton(
          onPressed: Navigator.of(context).pop,
          child: const Text('Close'),
        ),
      ],
    ),
  );
}
5
likes
0
pub points
76%
popularity

Publisher

verified publishergsconrad.com

Extremely powerful, reactive NoSQL database with typo-tolerant full-text search and declarative queries.

Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

flutter, mimir, path, path_provider

More

Packages that depend on flutter_mimir