mavix 0.1.1
mavix: ^0.1.1 copied to clipboard
A lightweight Flutter state manager with separate streams for persistent state and one-time UI activities.
example/lib/main.dart
import 'package:flutter/material.dart';
import 'package:mavix/mavix.dart';
void main() {
runApp(const ExampleApp());
}
/// A compact example designed for the pub.dev example tab.
///
/// It demonstrates:
/// - persistent UI state with [CounterState]
/// - one-time effects with [CounterActivity]
/// - reading Mavix from the widget tree
/// - rebuilding UI with [MavixSelector]
/// - reacting to effects with [MavixListener]
class ExampleApp extends StatelessWidget {
const ExampleApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Mavix Example',
home: MavixProvider<CounterMavix>(
create: (_) => CounterMavix(),
child: const CounterScreen(),
),
);
}
}
class CounterScreen extends StatelessWidget {
const CounterScreen({super.key});
@override
Widget build(BuildContext context) {
return MavixListener<CounterMavix, CounterActivity>(
listener: (context, activity) {
switch (activity) {
case MilestoneReached(:final value):
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('You reached $value taps'),
),
);
case CounterReset():
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Counter reset'),
),
);
}
},
child: Scaffold(
appBar: AppBar(
title: const Text('Mavix Counter'),
),
body: Center(
child: MavixSelector<CounterMavix, CounterState, int>(
selector: (state) => state.count,
builder: (context, count) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
const Text('Tap the buttons to update state'),
const SizedBox(height: 12),
Text(
'$count',
style: Theme.of(context).textTheme.displayMedium,
),
const SizedBox(height: 24),
Wrap(
spacing: 12,
children: [
FilledButton(
onPressed: () {
context.readMavix<CounterMavix>().increment();
},
child: const Text('Increment'),
),
OutlinedButton(
onPressed: count == 0
? null
: () {
context.readMavix<CounterMavix>().reset();
},
child: const Text('Reset'),
),
],
),
],
);
},
),
),
),
);
}
}
class CounterMavix extends Mavix<CounterState, CounterActivity> {
CounterMavix() : super(const CounterState());
void increment() {
final int nextCount = state.count + 1;
update(
state.copyWith(count: nextCount),
);
if (nextCount % 5 == 0) {
send(MilestoneReached(nextCount));
}
}
void reset() {
if (state.count == 0) {
return;
}
update(const CounterState());
send(const CounterReset());
}
}
class CounterState {
const CounterState({
this.count = 0,
});
final int count;
CounterState copyWith({
int? count,
}) {
return CounterState(
count: count ?? this.count,
);
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
other is CounterState &&
runtimeType == other.runtimeType &&
count == other.count;
}
@override
int get hashCode => count.hashCode;
}
sealed class CounterActivity {
const CounterActivity();
}
class MilestoneReached extends CounterActivity {
const MilestoneReached(this.value);
final int value;
}
class CounterReset extends CounterActivity {
const CounterReset();
}