Files
pixes/lib/foundation/state_controller.dart
2024-05-13 09:36:23 +08:00

195 lines
4.6 KiB
Dart

import 'package:flutter/material.dart';
import 'pair.dart';
class SimpleController extends StateController{
final void Function()? refresh_;
SimpleController({this.refresh_});
@override
void refresh() {
(refresh_ ?? super.refresh)();
}
}
abstract class StateController{
static final _controllers = <StateControllerWrapped>[];
static T put<T extends StateController>(T controller, {Object? tag, bool autoRemove = false}){
_controllers.add(StateControllerWrapped(controller, autoRemove, tag));
return controller;
}
static T putIfNotExists<T extends StateController>(T controller, {Object? tag, bool autoRemove = false}){
return findOrNull<T>(tag: tag) ?? put(controller, tag: tag, autoRemove: autoRemove);
}
static T find<T extends StateController>({Object? tag}){
try {
return _controllers.lastWhere((element) =>
element.controller is T
&& (tag == null || tag == element.tag)).controller as T;
}
catch(e){
throw StateError("${T.runtimeType} with tag $tag Not Found");
}
}
static T? findOrNull<T extends StateController>({Object? tag}){
try {
return _controllers.lastWhere((element) =>
element.controller is T
&& (tag == null || tag == element.tag)).controller as T;
}
catch(e){
return null;
}
}
static void remove<T>([Object? tag, bool check = false]){
for(int i=_controllers.length-1; i>=0; i--){
var element = _controllers[i];
if(element.controller is T && (tag == null || tag == element.tag)){
if(check && !element.autoRemove){
continue;
}
_controllers.removeAt(i);
return;
}
}
}
static SimpleController putSimpleController(void Function() onUpdate, Object? tag, {void Function()? refresh}){
var controller = SimpleController(refresh_: refresh);
controller.stateUpdaters.add(Pair(null, onUpdate));
_controllers.add(StateControllerWrapped(controller, false, tag));
return controller;
}
List<Pair<Object?, void Function()>> stateUpdaters = [];
void update([List<Object>? ids]){
if(ids == null){
for(var element in stateUpdaters){
element.right();
}
}else{
for(var element in stateUpdaters){
if(ids.contains(element.left)) {
element.right();
}
}
}
}
void dispose(){
_controllers.removeWhere((element) => element.controller == this);
}
void refresh(){
update();
}
}
class StateControllerWrapped{
StateController controller;
bool autoRemove;
Object? tag;
StateControllerWrapped(this.controller, this.autoRemove, this.tag);
}
class StateBuilder<T extends StateController> extends StatefulWidget {
const StateBuilder({super.key, this.init, this.dispose, this.initState, this.tag,
required this.builder, this.id});
final T? init;
final void Function(T controller)? dispose;
final void Function(T controller)? initState;
final Object? tag;
final Widget Function(T controller) builder;
Widget builderWrapped(StateController controller){
return builder(controller as T);
}
void initStateWrapped(StateController controller){
return initState?.call(controller as T);
}
void disposeWrapped(StateController controller){
return dispose?.call(controller as T);
}
final Object? id;
@override
State<StateBuilder> createState() => _StateBuilderState<T>();
}
class _StateBuilderState<T extends StateController> extends State<StateBuilder> {
late T controller;
@override
void initState() {
if(widget.init != null) {
StateController.put(widget.init!, tag: widget.tag, autoRemove: true);
}
try {
controller = StateController.find<T>(tag: widget.tag);
}
catch(e){
throw "Controller Not Found";
}
controller.stateUpdaters.add(Pair(widget.id, () {
if(mounted){
setState(() {});
}
}));
widget.initStateWrapped(controller);
super.initState();
}
@override
void dispose() {
widget.disposeWrapped(controller);
StateController.remove<T>(widget.tag, true);
super.dispose();
}
@override
Widget build(BuildContext context) => widget.builderWrapped(controller);
}
abstract class StateWithController<T extends StatefulWidget> extends State<T>{
late final SimpleController _controller;
void refresh(){
_controller.update();
}
@override
@mustCallSuper
void initState() {
_controller = StateController.putSimpleController(() => setState(() {}), tag, refresh: refresh);
super.initState();
}
@override
@mustCallSuper
void dispose() {
_controller.dispose();
super.dispose();
}
void update(){
_controller.update();
}
Object? get tag;
}