Created
November 30, 2020 05:10
-
-
Save Andrious/13763b23ace73aab029368c523abcd54 to your computer and use it in GitHub Desktop.
A Business Logic Component with access to the State object.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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