zeytin_state 0.0.1 copy "zeytin_state: ^0.0.1" to clipboard
zeytin_state: ^0.0.1 copied to clipboard

A lightning-fast, reactive state management solution built strictly for ZeytinX.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:zeytinx/zeytinx.dart';
import 'package:zeytin_state/zeytin_state.dart';

// 1. Initialize ZeytinX and ZeytinSync globally or via a service locator (e.g. get_it)
late final ZeytinX coreDB;
late final ZeytinSync zeytinSync;

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

  // 2. Setup Database
  coreDB = ZeytinX("my_app_namespace", "main_truck");
  await coreDB.initialize("./my_local_db"); // Adjust path for your platform

  // 3. Setup ZeytinSync State Manager
  zeytinSync = ZeytinSync(coreDB);
  zeytinSync.init();

  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Zeytin State Example',
      home: ProfileScreen(),
    );
  }
}

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

  @override
  State<ProfileScreen> createState() => _ProfileScreenState();
}

class _ProfileScreenState extends State<ProfileScreen> {
  // 4. Define your reactive states using ZM<T>
  late ZM<ZeytinXUserModel> myUser;
  late ZM<int> userScore;

  final String _userTag = "user_jea_123";

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

    // 5. Bind the state to a specific Box and Tag in the database.
    // Use the `mapper` to convert raw Map<String, dynamic> data to your custom Models.
    myUser = zeytinSync.bind<ZeytinXUserModel>(
      "users", // Database Box
      _userTag, // Document Tag
      ZeytinXUserModel.empty(), // Default value before fetch
      mapper: (dynamic data) {
        if (data == null) return ZeytinXUserModel.empty();
        return ZeytinXUserModel.fromJson(Map<String, dynamic>.from(data));
      },
    );

    // Binding a simple primitive type (No mapper needed)
    userScore = zeytinSync.bind<int>(
      "scores",
      _userTag,
      0, // Default value
      mapper: (dynamic data) => data?['score'] ?? 0,
    );

    _createInitialData();
  }

  Future<void> _createInitialData() async {
    // Create dummy data if it doesn't exist to show how UI reacts.
    bool exists = await coreDB.exists(box: "users", tag: _userTag);
    if (!exists) {
      var dummyUser = ZeytinXUserModel.empty().copyWith(
        uid: _userTag,
        username: "JeaFriday",
        biography: "Zeytin State is awesome!",
      );
      await coreDB.add(box: "users", tag: _userTag, value: dummyUser.toJson());
      await coreDB.add(box: "scores", tag: _userTag, value: {"score": 100});
    }
  }

  @override
  void dispose() {
    // 6. VERY IMPORTANT: Prevent memory leaks!
    // Unbind and dispose your ZMs when the widget is destroyed.
    zeytinSync.unbind("users", _userTag, myUser);
    zeytinSync.unbind("scores", _userTag, userScore);
    myUser.dispose();
    userScore.dispose();

    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("Zeytin State Example"),
        centerTitle: true,
        backgroundColor: Colors.green.shade700,
      ),
      body: Center(
        // 7. Use ZMListener to listen to one or multiple ZMs.
        // The UI will ONLY rebuild when the database data for these specific tags changes.
        child: ZMListener(
          listenables: [myUser, userScore],
          childBuilder: () {
            final user = myUser.value;
            final score = userScore.value;

            if (user.username.isEmpty) {
              return const CircularProgressIndicator();
            }

            return Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                CircleAvatar(
                  radius: 60,
                  backgroundColor: Colors.green.shade200,
                  child: Text(
                    user.username[0].toUpperCase(),
                    style: const TextStyle(fontSize: 40, color: Colors.white),
                  ),
                ),
                const SizedBox(height: 20),
                Text(
                  user.username,
                  style: const TextStyle(
                    fontSize: 28,
                    fontWeight: FontWeight.bold,
                  ),
                ),
                const SizedBox(height: 10),
                Text(
                  user.biography,
                  style: const TextStyle(fontSize: 18, color: Colors.grey),
                ),
                const SizedBox(height: 30),
                Container(
                  padding: const EdgeInsets.symmetric(
                    horizontal: 20,
                    vertical: 10,
                  ),
                  decoration: BoxDecoration(
                    color: Colors.green.shade50,
                    borderRadius: BorderRadius.circular(20),
                  ),
                  child: Text(
                    "Score: $score 🏆",
                    style: TextStyle(
                      fontSize: 20,
                      color: Colors.green.shade800,
                    ),
                  ),
                ),
              ],
            );
          },
        ),
      ),
      floatingActionButton: Column(
        mainAxisAlignment: MainAxisAlignment.end,
        children: [
          FloatingActionButton.extended(
            heroTag: "btn1",
            onPressed: () async {
              // 8. UPDATE THE DATABASE DIRECTLY!
              // Do NOT call setState() or myUser.set() manually.
              // ZeytinSync will detect the database write operation and update the UI automatically!
              await coreDB.update(
                box: "users",
                tag: _userTag,
                value: (currentValue) async {
                  currentValue["username"] = "Jea_${DateTime.now().second}";
                  currentValue["biography"] =
                      "Updated at: ${DateTime.now().toLocal().toString().split('.')[0]}";
                  return currentValue;
                },
              );
            },
            label: const Text("Change Profile"),
            icon: const Icon(Icons.person),
            backgroundColor: Colors.green.shade700,
          ),
          const SizedBox(height: 10),
          FloatingActionButton.extended(
            heroTag: "btn2",
            onPressed: () async {
              // Same here, just update the database.
              await coreDB.update(
                box: "scores",
                tag: _userTag,
                value: (current) async {
                  current["score"] = (current["score"] ?? 0) + 10;
                  return current;
                },
              );
            },
            label: const Text("Add +10 Score"),
            icon: const Icon(Icons.add),
            backgroundColor: Colors.orange.shade700,
          ),
        ],
      ),
    );
  }
}
1
likes
150
points
0
downloads

Publisher

verified publisherjeafriday.com

Weekly Downloads

A lightning-fast, reactive state management solution built strictly for ZeytinX.

Documentation

API reference

License

BSD-3-Clause (license)

Dependencies

flutter, zeytinx

More

Packages that depend on zeytin_state