A Business Logic Component with access to the State object.
import 'package:flutter/material.dart'; | |
class Bloc extends StateSetter { | |
// | |
Bloc([StateBloc state]) : super() { | |
// Associate it with the specified State object. | |
addState(state); | |
// Include it in a collection of Blocs. | |
if (!_blocs.containsValue(this)) { | |
_blocs.addAll({this.runtimeType: this}); | |
} | |
} | |
/// Associate this Controller to the specified State object | |
/// to use that State object's functions and features. | |
bool addState(StateBloc state) { | |
if (state == null) { | |
return false; | |
} | |
return pushState(state); | |
} | |
/// The current StateBloc object. | |
StateBloc get stateBloc => _stateBloc; | |
/// The current State object. | |
State get state => _stateBloc; | |
/// Retrieve an existing Bloc by type. | |
/// Note There can't be more than one of the same type. | |
/// It retrieves the last one entered. | |
static T of<T extends Bloc>() => _blocs[_type<T>()]; | |
static Map<Type, Bloc> _blocs = Map(); | |
static Type _type<T>() => T; | |
} | |
/// Allows you to call 'setState' for the current the State object. | |
class StateSetter with StateSets { | |
/// Provide the setState() function to external actors | |
void setState(VoidCallback fn) => _stateBloc?.setState(fn); | |
/// Allows external classes to 'refresh' or 'rebuild' the widget tree. | |
void refresh() => _stateBloc?.refresh(); | |
/// Allow for a more accurate description | |
void rebuild() => refresh(); | |
/// For those accustom to the 'Provider' approach. | |
void notifyListeners() => refresh(); | |
} | |
/// Record in a Set any previous State objects | |
/// and the current State object being used. | |
mixin StateSets { | |
StateBloc _stateBloc; | |
final Set<StateBloc> _stateMVCSet = {}; | |
bool pushState(StateBloc state) { | |
if (state == null) { | |
return false; | |
} | |
_stateBloc = state; | |
return _stateMVCSet.add(state); | |
} | |
bool removeState(StateBloc state) { | |
if (state == null) { | |
return false; | |
} | |
if (state == _stateBloc) { | |
return popState(); | |
} | |
return _stateMVCSet.remove(state); | |
} | |
bool popState() { | |
// Don't continue if null. | |
if (_stateBloc == null) { | |
return false; | |
} | |
// Remove the 'current' state | |
final removed = _stateMVCSet.remove(_stateBloc); | |
// Reassign the last state object. | |
if (_stateMVCSet.isEmpty) { | |
_stateBloc = null; | |
} else { | |
_stateBloc = _stateMVCSet.last; | |
} | |
return removed; | |
} | |
/// Return a 'copy' of the Set of State objects. | |
Set<StateBloc> get states => Set.from(_stateMVCSet.whereType<StateBloc>()); | |
} | |
abstract class StateBloc<T extends StatefulWidget> | |
extends State<StatefulWidget> { | |
// | |
@override | |
Widget build(BuildContext context); | |
/// You need to be able access the widget. | |
@override | |
T get widget => super.widget; | |
/// Register this bloc with this State object. | |
bool addBloc(Bloc bloc) => bloc.pushState(this); | |
/// Call the State object's setState() function. | |
@override | |
void setState(VoidCallback fn) => super.setState(fn); | |
/// Allows the user to call setState(). | |
/// Refresh the interface by 'rebuilding' the Widget Tree | |
void refresh() => setState(() {}); | |
} | |
// Exposes the [read] method. | |
extension ReadContext on BuildContext { | |
/// Obtain a value from the nearest ancestor provider of type [T]. | |
/// | |
T read<T extends Bloc>() { | |
return Bloc.of<T>(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment