Skip to main content

bingo 1.2.0 copy "bingo: ^1.2.0" to clipboard
bingo: ^1.2.0 copied to clipboard

A high-performance, synchronous state storage engine for Flutter with built-in caching and type-safe object registration.

example/main.dart

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

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Bingo.setup();

  // Mapping the User factory for Bingo's deep casting logic
  Bingo.register<User>((json) => User.fromJson(json));

  runApp(const BingoExampleApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData.dark().copyWith(
        scaffoldBackgroundColor: const Color(0xFF0D1117),
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.cyanAccent, brightness: Brightness.dark),
      ),
      home: const BingoDashboard(),
    );
  }
}

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

  @override
  State<BingoDashboard> createState() => _BingoDashboardState();
}

class _BingoDashboardState extends State<BingoDashboard> {
  final List<String> _logs = ["👾 Bingo Console Active"];

  // Controllers for User Object Input
  final _uIdCtrl = TextEditingController();
  final _uNameCtrl = TextEditingController();
  final _uEmailCtrl = TextEditingController();
  final _uKeyCtrl = TextEditingController();

  // Controllers for Retrieval & Deletion
  final _queryCtrl = TextEditingController();
  final _deleteCtrl = TextEditingController();

  dynamic _queryResult;
  String _resultType = "None";

  void _log(String msg) => setState(() => _logs.insert(0, "[${DateTime.now().second}s] $msg"));

  void _fetchData() {
    final key = _queryCtrl.text.trim();
    if (key.isEmpty) {
      setState(() {
        _queryResult = null;
        _resultType = "None";
      });
      return;
    }

    // Try User first, fallback to dynamic if null
    final result = Bingo.call<User>(key) ?? Bingo.call<dynamic>(key);

    setState(() {
      _queryResult = result;
      _resultType = result?.runtimeType.toString() ?? "Null";
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("B I N G O", style: TextStyle(letterSpacing: 4, fontWeight: FontWeight.bold)),
        elevation: 0,
        centerTitle: true,
        foregroundColor: Colors.cyanAccent,
        backgroundColor: Colors.transparent,
        surfaceTintColor: Colors.transparent,
      ),
      body: SingleChildScrollView(
        padding: const EdgeInsets.all(20),
        child: Column(
          children: [
            // 1. USER GENERATOR (Now the main entry point)
            _sectionHeader("USER GENERATOR"),
            _glassContainer(
              child: Column(
                children: [
                  TextField(
                    controller: _uKeyCtrl,
                    decoration: const InputDecoration(labelText: "Storage Key (Unique)", prefixIcon: Icon(Icons.key, size: 18)),
                  ),
                  const SizedBox(height: 10),
                  Row(
                    children: [
                      Expanded(
                        child: TextField(
                          controller: _uIdCtrl,
                          decoration: const InputDecoration(labelText: "User ID"),
                        ),
                      ),
                      const SizedBox(width: 10),
                      Expanded(
                        child: TextField(
                          controller: _uNameCtrl,
                          decoration: const InputDecoration(labelText: "Name"),
                        ),
                      ),
                    ],
                  ),
                  TextField(
                    controller: _uEmailCtrl,
                    decoration: const InputDecoration(labelText: "Email Address"),
                  ),
                  const SizedBox(height: 20),
                  _neonButton(
                    text: "GENERATE & MARK USER",
                    onTap: () async {
                      if (_uKeyCtrl.text.isEmpty) {
                        _log("⚠️ Error: Storage Key is required.");
                        return;
                      }
                      final user = User(id: _uIdCtrl.text, name: _uNameCtrl.text, email: _uEmailCtrl.text);
                      await Bingo.mark(_uKeyCtrl.text, user);
                      _log("👤 User '${user.name}' marked at key '${_uKeyCtrl.text}'");
                      _uKeyCtrl.clear();
                      _uIdCtrl.clear();
                      _uNameCtrl.clear();
                      _uEmailCtrl.clear();
                      setState(() {});
                    },
                  ),
                ],
              ),
            ),
            const SizedBox(height: 25),

            // 2. SETTINGS DEMO (Merge behavior)
            _sectionHeader("SETTINGS DEMO"),
            _glassContainer(
              child: Column(
                children: [
                  const Text("Bingo.mark auto-merges Maps by default.", style: TextStyle(fontSize: 11, color: Colors.grey)),
                  const SizedBox(height: 12),
                  Row(
                    children: [
                      Expanded(
                        child: _neonButton(
                          text: "SAVE SETTINGS",
                          onTap: () async {
                            await Bingo.mark('settings', {'theme': 'light'});
                            _log("⚙️ Settings saved (theme: light)");
                            setState(() {});
                          },
                        ),
                      ),
                      const SizedBox(width: 10),
                      Expanded(
                        child: _neonButton(
                          text: "MERGE LANG",
                          color: Colors.amber,
                          onTap: () async {
                            await Bingo.mark('settings', {'lang': 'en'});
                            _log("🔀 Merged lang: en (theme kept)");
                            setState(() {});
                          },
                        ),
                      ),
                    ],
                  ),
                  const SizedBox(height: 10),
                  _neonButton(
                    text: "OVERWRITE (MERGE: FALSE)",
                    color: Colors.purpleAccent,
                    onTap: () async {
                      await Bingo.mark('settings', {'theme': 'dark'}, merge: false);
                      _log("💜 Settings overwritten (lang lost)");
                      setState(() {});
                    },
                  ),
                ],
              ),
            ),
            const SizedBox(height: 25),

            // 3. RETRIEVAL MODULE
            _sectionHeader("USER DATA RETRIEVAL"),
            _glassContainer(
              child: Column(
                children: [
                  TextField(
                    controller: _queryCtrl,
                    onChanged: (_) => _fetchData(),
                    decoration: const InputDecoration(labelText: "Enter Key to Fetch", prefixIcon: Icon(Icons.search)),
                  ),
                  const SizedBox(height: 15),
                  Container(
                    width: double.infinity,
                    padding: const EdgeInsets.all(12),
                    decoration: BoxDecoration(color: Colors.black, borderRadius: BorderRadius.circular(8)),
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        Text("TYPE: $_resultType", style: const TextStyle(color: Colors.cyanAccent, fontSize: 10)),
                        const Divider(color: Colors.white10),
                        Text(
                          _queryResult?.toString() ?? "No record found",
                          style: TextStyle(fontSize: 13, color: _queryResult == null ? Colors.grey : Colors.white, fontFamily: 'monospace'),
                        ),
                        const SizedBox(height: 6),
                        Text("EXISTS: ${_queryCtrl.text.trim().isMarked}", style: TextStyle(fontSize: 10, color: _queryCtrl.text.trim().isMarked ? Colors.greenAccent : Colors.redAccent)),
                      ],
                    ),
                  ),
                ],
              ),
            ),
            const SizedBox(height: 25),

            // 3. DESTRUCTION MODULE (Delete & Clear)
            _sectionHeader("DESTRUCTION MODULE"),
            _glassContainer(
              child: Column(
                children: [
                  TextField(
                    controller: _deleteCtrl,
                    decoration: const InputDecoration(
                      labelText: "Key to Erase",
                      prefixIcon: Icon(Icons.delete_outline, color: Colors.redAccent),
                    ),
                  ),
                  const SizedBox(height: 15),
                  Row(
                    children: [
                      Expanded(
                        child: _neonButton(
                          text: "ERASE KEY",
                          color: Colors.redAccent,
                          onTap: () async {
                            if (_deleteCtrl.text.isNotEmpty) {
                              await Bingo.erase(_deleteCtrl.text);
                              _log("🗑️ Erased key: ${_deleteCtrl.text}");
                              _deleteCtrl.clear();
                              _fetchData(); // Update retrieval if current key was deleted
                            }
                          },
                        ),
                      ),
                      const SizedBox(width: 12),
                      Expanded(
                        child: _neonButton(
                          text: "CLEAR ALL",
                          color: Colors.orangeAccent,
                          onTap: () async {
                            await Bingo.clear();
                            _log("☢️ DATABASE WIPED");
                            _fetchData();
                            setState(() {});
                          },
                        ),
                      ),
                    ],
                  ),
                ],
              ),
            ),
            const SizedBox(height: 25),

            // 4. LOGS
            _sectionHeader("SYSTEM LOGS"),
            Container(
              height: 120,
              width: double.infinity,
              padding: const EdgeInsets.all(10),
              decoration: BoxDecoration(
                color: Colors.black,
                borderRadius: BorderRadius.circular(10),
                border: Border.all(color: Colors.white10),
              ),
              child: ListView.builder(
                itemCount: _logs.length,
                itemBuilder: (context, i) => Text(
                  _logs[i],
                  style: const TextStyle(color: Colors.greenAccent, fontFamily: 'monospace', fontSize: 11),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }

  // --- REUSABLE UI BUILDERS ---

  Widget _sectionHeader(String title) {
    return Align(
      alignment: Alignment.centerLeft,
      child: Padding(
        padding: const EdgeInsets.only(bottom: 8, left: 4),
        child: Text(
          title,
          style: const TextStyle(fontSize: 10, fontWeight: FontWeight.bold, color: Colors.grey, letterSpacing: 1.5),
        ),
      ),
    );
  }

  Widget _glassContainer({required Widget child}) {
    return Container(
      decoration: BoxDecoration(
        border: Border.all(color: Colors.cyanAccent.withAlpha(40)),
        borderRadius: BorderRadius.circular(15),
        gradient: LinearGradient(begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [Colors.cyan.withAlpha(15), Colors.transparent]),
      ),
      padding: const EdgeInsets.all(16),
      child: child,
    );
  }

  Widget _neonButton({required String text, required VoidCallback onTap, Color color = Colors.cyanAccent}) {
    return InkWell(
      onTap: onTap,
      borderRadius: BorderRadius.circular(999),
      child: Container(
        padding: const EdgeInsets.all(12),
        alignment: Alignment.center,
        decoration: BoxDecoration(
          border: Border.all(color: color.withAlpha(80)),
          borderRadius: BorderRadius.circular(999),
          gradient: LinearGradient(colors: [color.withAlpha(60), Colors.transparent]),
        ),
        child: Text(
          text,
          style: TextStyle(fontSize: 11, fontWeight: FontWeight.bold, color: color),
        ),
      ),
    );
  }
}

class User {
  final String id, name, email;

  User({required this.id, required this.name, required this.email});

  factory User.fromJson(Map<String, dynamic> json) => User(id: json['id'], name: json['name'], email: json['email']);

  Map<String, dynamic> toJson() => {'id': id, 'name': name, 'email': email};

  @override
  String toString() => "User(ID: $id, Name: $name, Email: $email)";
}
3
likes
160
points
163
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

A high-performance, synchronous state storage engine for Flutter with built-in caching and type-safe object registration.

Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

flutter, path_provider, sembast, sembast_web

More

Packages that depend on bingo