Skip to content

Instantly share code, notes, and snippets.

@Andrious
Created November 30, 2020 05:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Andrious/13763b23ace73aab029368c523abcd54 to your computer and use it in GitHub Desktop.
Save Andrious/13763b23ace73aab029368c523abcd54 to your computer and use it in GitHub Desktop.
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