minix 1.0.0 copy "minix: ^1.0.0" to clipboard
minix: ^1.0.0 copied to clipboard

A powerful, lightweight state management and dependency injection solution for Flutter applications with reactive programming capabilities.

example/main.dart

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

void main() {
  // Enable DI logging for development
  Injector.enableLogs = true;

  // Register dependencies
  _setupDependencies();

  runApp(const MyApp());
}

void _setupDependencies() {
  // Register services
  Injector.put<CounterService>(CounterService());
  Injector.lazyPut<ApiService>(() => ApiService());

  // Register ViewModels
  Injector.lazyPut<CounterViewModel>(() => CounterViewModel());
  Injector.lazyPut<UserViewModel>(() => UserViewModel());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Minix Demo',
      theme: ThemeData(primarySwatch: Colors.blue),
      home: const HomeScreen(),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Minix Examples')),
      body: ListView(
        padding: const EdgeInsets.all(16),
        children: [
          _buildExampleCard(
            'Basic Counter',
            'Simple reactive counter with Observer',
                () => Navigator.push(context,
                MaterialPageRoute(builder: (_) => CounterScreen())),
          ),
          _buildExampleCard(
            'Async Operations',
            'Loading states with AsyncObservable',
                () => Navigator.push(context,
                MaterialPageRoute(builder: (_) => AsyncScreen())),
          ),
          _buildExampleCard(
            'Stream Example',
            'Real-time data with StreamObservable',
                () => Navigator.push(context,
                MaterialPageRoute(builder: (_) => StreamScreen())),
          ),
          _buildExampleCard(
            'MVVM Pattern',
            'Architecture example with DI',
                () => Navigator.push(context,
                MaterialPageRoute(builder: (_) => const MVVMScreen())),
          ),
        ],
      ),
    );
  }

  Widget _buildExampleCard(String title, String subtitle, VoidCallback onTap) {
    return Card(
      margin: const EdgeInsets.only(bottom: 16),
      child: ListTile(
        title: Text(title, style: const TextStyle(fontWeight: FontWeight.bold)),
        subtitle: Text(subtitle),
        trailing: const Icon(Icons.arrow_forward_ios),
        onTap: onTap,
      ),
    );
  }
}

// =============================================================================
// BASIC COUNTER EXAMPLE
// =============================================================================

class CounterScreen extends StatelessWidget {

  CounterScreen({super.key});
  final counter = Observable(0);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Basic Counter')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Text('Counter Value:'),
            const SizedBox(height: 16),
            // Observer automatically rebuilds when counter.value changes
            Observer(() {
              return Text(
                '${counter.value}',

              );
            }),
            const SizedBox(height: 32),
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: [
                ElevatedButton(
                  onPressed: () => counter.value--,
                  child: const Text('-'),
                ),
                ElevatedButton(
                  onPressed: () => counter.value = 0,
                  child: const Text('Reset'),
                ),
                ElevatedButton(
                  onPressed: () => counter.value++,
                  child: const Text('+'),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

// =============================================================================
// ASYNC OPERATIONS EXAMPLE
// =============================================================================

class AsyncScreen extends StatelessWidget {

  AsyncScreen({super.key});
  final userAsync = AsyncObservable<User>();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Async Operations')),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            ElevatedButton(
              onPressed: () => _loadUser(),
              child: const Text('Load User Data'),
            ),
            const SizedBox(height: 20),
            Expanded(
              child: Observer(() {
                // Reactive UI based on async state
                if (userAsync.isLoading) {
                  return const Center(
                    child: Column(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: [
                        CircularProgressIndicator(),
                        SizedBox(height: 16),
                        Text('Loading user data...'),
                      ],
                    ),
                  );
                }

                if (userAsync.hasError) {
                  return Center(
                    child: Column(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: [
                        const Icon(Icons.error, color: Colors.red, size: 64),
                        const SizedBox(height: 16),
                        Text(
                          'Error: ${userAsync.error}',
                          style: const TextStyle(color: Colors.red),
                          textAlign: TextAlign.center,
                        ),
                        const SizedBox(height: 16),
                        ElevatedButton(
                          onPressed: () => _loadUser(),
                          child: const Text('Retry'),
                        ),
                      ],
                    ),
                  );
                }

                if (userAsync.hasData) {
                  final user = userAsync.data!;
                  return Center(
                    child: Card(
                      child: Padding(
                        padding: const EdgeInsets.all(16),
                        child: Column(
                          mainAxisSize: MainAxisSize.min,
                          children: [
                            CircleAvatar(
                              radius: 50,
                              child: Text(user.name[0]),
                            ),
                            const SizedBox(height: 16),
                            Text(
                              user.name,

                            ),
                            Text(user.email),
                            const SizedBox(height: 16),
                            Text(
                              'ID: ${user.id}',
                              style: const TextStyle(color: Colors.grey),
                            ),
                          ],
                        ),
                      ),
                    ),
                  );
                }

                return const Center(
                  child: Text('No data loaded yet'),
                );
              }),
            ),
          ],
        ),
      ),
    );
  }

  Future<void> _loadUser() async {
    await userAsync.execute(() async {
      // Simulate API call
      await Future.delayed(const Duration(seconds: 2));

      // Simulate random success/error
      if (DateTime.now().millisecond % 3 == 0) {
        throw Exception('Network error occurred');
      }

      return User(
        id: '${DateTime.now().millisecond}',
        name: 'John Doe',
        email: 'john.doe@example.com',
      );
    });
  }
}

// =============================================================================
// STREAM EXAMPLE
// =============================================================================

class StreamScreen extends StatelessWidget {

  StreamScreen({super.key});
  final messageStream = StreamObservable<String>();
  final messages = Observable<List<String>>([]);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Stream Example')),
      body: Column(
        children: [
          Padding(
            padding: const EdgeInsets.all(16),
            child: Row(
              children: [
                Expanded(
                  child: ElevatedButton(
                    onPressed: () => _startStream(),
                    child: const Text('Start Stream'),
                  ),
                ),
                const SizedBox(width: 8),
                Expanded(
                  child: ElevatedButton(
                    onPressed: () => _stopStream(),
                    child: const Text('Stop Stream'),
                  ),
                ),
              ],
            ),
          ),
          Expanded(
            child: Observer(() {
              return ListView.builder(
                itemCount: messages.value.length,
                itemBuilder: (context, index) {
                  final message = messages.value[index];
                  return ListTile(
                    leading: const Icon(Icons.message),
                    title: Text(message),
                    subtitle: Text('Received at ${DateTime.now().toString().substring(11, 19)}'),
                  );
                },
              );
            }),
          ),
          Observer(() {
            return Container(
              padding: const EdgeInsets.all(16),
              color: messageStream.isListening ? Colors.green[100] : Colors.grey[100],
              child: Row(
                children: [
                  Icon(
                    messageStream.isListening ? Icons.radio_button_checked : Icons.radio_button_off,
                    color: messageStream.isListening ? Colors.green : Colors.grey,
                  ),
                  const SizedBox(width: 8),
                  Text(
                    messageStream.isListening ? 'Stream Active' : 'Stream Inactive',
                    style: TextStyle(
                      color: messageStream.isListening ? Colors.green[800] : Colors.grey[800],
                      fontWeight: FontWeight.bold,
                    ),
                  ),
                ],
              ),
            );
          }),
        ],
      ),
    );
  }

  void _startStream() {
    // Create a sample stream
    final stream = Stream.periodic(
      const Duration(seconds: 1),
          (index) => 'Message ${index + 1}: ${DateTime.now().toString().substring(11, 19)}',
    );

    messageStream.listen(
      stream,
      onData: (message) {
        // Add to messages list
        final currentMessages = List<String>.from(messages.value);
        currentMessages.insert(0, message);

        // Keep only last 10 messages
        if (currentMessages.length > 10) {
          currentMessages.removeLast();
        }

        messages.value = currentMessages;
      },
    );
  }

  Future<void> _stopStream() async {
    await messageStream.cancel();
  }
}

// =============================================================================
// MVVM PATTERN EXAMPLE
// =============================================================================

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

  @override
  Widget build(BuildContext context) {
    final viewModel = Injector.find<CounterViewModel>();

    return Scaffold(
      appBar: AppBar(title: const Text('MVVM Pattern')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Observer(() {
              return Text(
                'Counter: ${viewModel.counter}',
              );
            }),
            const SizedBox(height: 16),
            Observer(() {
              return Text(
                'Status: ${viewModel.status}',
                style: TextStyle(
                  color: viewModel.isEven ? Colors.green : Colors.orange,
                  fontWeight: FontWeight.bold,
                ),
              );
            }),
            const SizedBox(height: 32),
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: [
                ElevatedButton(
                  onPressed: viewModel.decrement,
                  child: const Text('- Decrement'),
                ),
                ElevatedButton(
                  onPressed: viewModel.reset,
                  child: const Text('Reset'),
                ),
                ElevatedButton(
                  onPressed: viewModel.increment,
                  child: const Text('+ Increment'),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

// =============================================================================
// MODELS & SERVICES
// =============================================================================

class User {

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

class CounterService {
  final _counter = Observable(0);

  int get counter => _counter.value;
  Observable<int> get counterObservable => _counter;

  void increment() => _counter.value++;
  void decrement() => _counter.value--;
  void reset() => _counter.value = 0;
}

class ApiService {
  Future<User> fetchUser(String id) async {
    await Future.delayed(const Duration(seconds: 1));
    return User(id: id, name: 'API User', email: 'api@example.com');
  }
}

class CounterViewModel {
  final CounterService _service = Injector.find<CounterService>();

  int get counter => _service.counter;

  String get status => isEven ? 'Even Number' : 'Odd Number';

  bool get isEven => _service.counter % 2 == 0;

  void increment() => _service.increment();
  void decrement() => _service.decrement();
  void reset() => _service.reset();
}

class UserViewModel {
  final _user = AsyncObservable<User>();
  final ApiService _api = Injector.find<ApiService>();

  AsyncObservable<User> get user => _user;

  Future<void> loadUser(String id) async {
    await _user.execute(() => _api.fetchUser(id));
  }
}
2
likes
0
points
33
downloads

Publisher

unverified uploader

Weekly Downloads

A powerful, lightweight state management and dependency injection solution for Flutter applications with reactive programming capabilities.

Repository (GitHub)
View/report issues

Topics

#state-management #dependency-injection #reactive-programming #flutter #observables

License

unknown (license)

Dependencies

flutter

More

Packages that depend on minix