new change to use intaleq_map sdk 04-16-4

This commit is contained in:
Hamza-Ayed
2026-04-16 19:45:03 +03:00
parent 0aa1f15f25
commit a54a7a4189
850 changed files with 83282 additions and 3075 deletions

View File

@@ -0,0 +1,42 @@
import 'package:flutter/material.dart';
import '../../../get.dart';
/// Unlike GetxController, which serves to control events on each of its pages,
/// GetxService is not automatically disposed (nor can be removed with
/// Get.delete()).
/// It is ideal for situations where, once started, that service will
/// remain in memory, such as Auth control for example. Only way to remove
/// it is Get.reset().
abstract class GetxService extends DisposableInterface with GetxServiceMixin {}
abstract class DisposableInterface extends GetLifeCycle {
/// Called immediately after the widget is allocated in memory.
/// You might use this to initialize something for the controller.
@override
@mustCallSuper
void onInit() {
super.onInit();
Get.engine.addPostFrameCallback((_) => onReady());
}
/// Called 1 frame after onInit(). It is the perfect place to enter
/// navigation events, like snackbar, dialogs, or a new route, or
/// async request.
@override
void onReady() {
super.onReady();
}
/// Called before [onDelete] method. [onClose] might be used to
/// dispose resources used by the controller. Like closing events,
/// or streams before the controller is destroyed.
/// Or dispose objects that can potentially create some memory leaks,
/// like TextEditingControllers, AnimationControllers.
/// Might be useful as well to persist some data on disk.
@override
void onClose() {
super.onClose();
}
}

View File

@@ -0,0 +1,133 @@
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import '../../../get_core/get_core.dart';
import '../../../get_instance/src/get_instance.dart';
import '../../../get_rx/src/rx_types/rx_types.dart';
import '../../get_state_manager.dart';
typedef GetXControllerBuilder<T extends DisposableInterface> = Widget Function(
T controller);
class GetX<T extends DisposableInterface> extends StatefulWidget {
final GetXControllerBuilder<T> builder;
final bool global;
// final Stream Function(T) stream;
// final StreamController Function(T) streamController;
final bool autoRemove;
final bool assignId;
final void Function(GetXState<T> state)? initState,
dispose,
didChangeDependencies;
final void Function(GetX oldWidget, GetXState<T> state)? didUpdateWidget;
final T? init;
final String? tag;
const GetX({
this.tag,
required this.builder,
this.global = true,
this.autoRemove = true,
this.initState,
this.assignId = false,
// this.stream,
this.dispose,
this.didChangeDependencies,
this.didUpdateWidget,
this.init,
// this.streamController
});
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties
..add(
DiagnosticsProperty<T>('controller', init),
)
..add(DiagnosticsProperty<String>('tag', tag))
..add(
ObjectFlagProperty<GetXControllerBuilder<T>>.has('builder', builder));
}
@override
GetXState<T> createState() => GetXState<T>();
}
class GetXState<T extends DisposableInterface> extends State<GetX<T>> {
final _observer = RxNotifier();
T? controller;
bool? _isCreator = false;
late StreamSubscription _subs;
@override
void initState() {
// var isPrepared = GetInstance().isPrepared<T>(tag: widget.tag);
final isRegistered = GetInstance().isRegistered<T>(tag: widget.tag);
if (widget.global) {
if (isRegistered) {
_isCreator = GetInstance().isPrepared<T>(tag: widget.tag);
controller = GetInstance().find<T>(tag: widget.tag);
} else {
controller = widget.init;
_isCreator = true;
GetInstance().put<T>(controller!, tag: widget.tag);
}
} else {
controller = widget.init;
_isCreator = true;
controller?.onStart();
}
widget.initState?.call(this);
if (widget.global && Get.smartManagement == SmartManagement.onlyBuilder) {
controller?.onStart();
}
_subs = _observer.listen((data) => setState(() {}), cancelOnError: false);
super.initState();
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
if (widget.didChangeDependencies != null) {
widget.didChangeDependencies!(this);
}
}
@override
void didUpdateWidget(GetX oldWidget) {
super.didUpdateWidget(oldWidget as GetX<T>);
widget.didUpdateWidget?.call(oldWidget, this);
}
@override
void dispose() {
if (widget.dispose != null) widget.dispose!(this);
if (_isCreator! || widget.assignId) {
if (widget.autoRemove && GetInstance().isRegistered<T>(tag: widget.tag)) {
GetInstance().delete<T>(tag: widget.tag);
}
}
_subs.cancel();
_observer.close();
controller = null;
_isCreator = null;
super.dispose();
}
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.add(DiagnosticsProperty<T>('controller', controller));
}
@override
Widget build(BuildContext context) => RxInterface.notifyChildren(
_observer,
() => widget.builder(controller!),
);
}

View File

@@ -0,0 +1,197 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import '../../../instance_manager.dart';
import '../../get_state_manager.dart';
import '../simple/list_notifier.dart';
mixin StateMixin<T> on ListNotifierMixin {
T? _value;
RxStatus? _status;
bool _isNullOrEmpty(dynamic val) {
if (val == null) return true;
var result = false;
if (val is Iterable) {
result = val.isEmpty;
} else if (val is String) {
result = val.isEmpty;
} else if (val is Map) {
result = val.isEmpty;
}
return result;
}
void _fillEmptyStatus() {
_status = _isNullOrEmpty(_value) ? RxStatus.loading() : RxStatus.success();
}
RxStatus get status {
notifyChildrens();
return _status ??= _status = RxStatus.loading();
}
T? get state => value;
@protected
T? get value {
notifyChildrens();
return _value;
}
@protected
set value(T? newValue) {
if (_value == newValue) return;
_value = newValue;
refresh();
}
@protected
void change(T? newState, {RxStatus? status}) {
var _canUpdate = false;
if (status != null) {
_status = status;
_canUpdate = true;
}
if (newState != _value) {
_value = newState;
_canUpdate = true;
}
if (_canUpdate) {
refresh();
}
}
void append(Future<T> Function() body(), {String? errorMessage}) {
final compute = body();
compute().then((newValue) {
change(newValue, status: RxStatus.success());
}, onError: (err) {
change(state, status: RxStatus.error(errorMessage ?? err.toString()));
});
}
}
class Value<T> extends ListNotifier
with StateMixin<T>
implements ValueListenable<T?> {
Value(T val) {
_value = val;
_fillEmptyStatus();
}
@override
T? get value {
notifyChildrens();
return _value;
}
@override
set value(T? newValue) {
if (_value == newValue) return;
_value = newValue;
refresh();
}
T? call([T? v]) {
if (v != null) {
value = v;
}
return value;
}
void update(void fn(T? value)) {
fn(value);
refresh();
}
@override
String toString() => value.toString();
dynamic toJson() => (value as dynamic)?.toJson();
}
extension ReactiveT<T> on T {
Value<T> get reactive => Value<T>(this);
}
typedef Condition = bool Function();
abstract class GetNotifier<T> extends Value<T> with GetLifeCycleBase {
GetNotifier(T initial) : super(initial) {
$configureLifeCycle();
}
@override
@mustCallSuper
void onInit() {
super.onInit();
ambiguate(SchedulerBinding.instance)
?.addPostFrameCallback((_) => onReady());
}
}
extension StateExt<T> on StateMixin<T> {
Widget obx(
NotifierBuilder<T?> widget, {
Widget Function(String? error)? onError,
Widget? onLoading,
Widget? onEmpty,
}) {
return SimpleBuilder(builder: (_) {
if (status.isLoading) {
return onLoading ?? const Center(child: CircularProgressIndicator());
} else if (status.isError) {
return onError != null
? onError(status.errorMessage)
: Center(child: Text('A error occurred: ${status.errorMessage}'));
} else if (status.isEmpty) {
return onEmpty != null
? onEmpty
: SizedBox.shrink(); // Also can be widget(null); but is risky
}
return widget(value);
});
}
}
class RxStatus {
final bool isLoading;
final bool isError;
final bool isSuccess;
final bool isEmpty;
final bool isLoadingMore;
final String? errorMessage;
RxStatus._({
this.isEmpty = false,
this.isLoading = false,
this.isError = false,
this.isSuccess = false,
this.errorMessage,
this.isLoadingMore = false,
});
factory RxStatus.loading() {
return RxStatus._(isLoading: true);
}
factory RxStatus.loadingMore() {
return RxStatus._(isSuccess: true, isLoadingMore: true);
}
factory RxStatus.success() {
return RxStatus._(isSuccess: true);
}
factory RxStatus.error([String? message]) {
return RxStatus._(isError: true, errorMessage: message);
}
factory RxStatus.empty() {
return RxStatus._(isEmpty: true);
}
}
typedef NotifierBuilder<T> = Widget Function(T state);

View File

@@ -0,0 +1,92 @@
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import '../../../get_rx/src/rx_types/rx_types.dart';
typedef WidgetCallback = Widget Function();
/// The [ObxWidget] is the base for all GetX reactive widgets
///
/// See also:
/// - [Obx]
/// - [ObxValue]
abstract class ObxWidget extends StatefulWidget {
const ObxWidget({Key? key}) : super(key: key);
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties..add(ObjectFlagProperty<Function>.has('builder', build));
}
@override
_ObxState createState() => _ObxState();
@protected
Widget build();
}
class _ObxState extends State<ObxWidget> {
final _observer = RxNotifier();
late StreamSubscription subs;
@override
void initState() {
super.initState();
subs = _observer.listen(_updateTree, cancelOnError: false);
}
void _updateTree(_) {
if (mounted) {
setState(() {});
}
}
@override
void dispose() {
subs.cancel();
_observer.close();
super.dispose();
}
@override
Widget build(BuildContext context) =>
RxInterface.notifyChildren(_observer, widget.build);
}
/// The simplest reactive widget in GetX.
///
/// Just pass your Rx variable in the root scope of the callback to have it
/// automatically registered for changes.
///
/// final _name = "GetX".obs;
/// Obx(() => Text( _name.value )),... ;
class Obx extends ObxWidget {
final WidgetCallback builder;
const Obx(this.builder);
@override
Widget build() => builder();
}
/// Similar to Obx, but manages a local state.
/// Pass the initial data in constructor.
/// Useful for simple local states, like toggles, visibility, themes,
/// button states, etc.
/// Sample:
/// ObxValue((data) => Switch(
/// value: data.value,
/// onChanged: (flag) => data.value = flag,
/// ),
/// false.obs,
/// ),
class ObxValue<T extends RxInterface> extends ObxWidget {
final Widget Function(T) builder;
final T data;
const ObxValue(this.builder, this.data, {Key? key}) : super(key: key);
@override
Widget build() => builder(data);
}

View File

@@ -0,0 +1,203 @@
// ignore_for_file: lines_longer_than_80_chars
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import '../../get_state_manager.dart';
/// Used like `SingleTickerProviderMixin` but only with Get Controllers.
/// Simplifies AnimationController creation inside GetxController.
///
/// Example:
///```
///class SplashController extends GetxController with
/// GetSingleTickerProviderStateMixin {
/// AnimationController controller;
///
/// @override
/// void onInit() {
/// final duration = const Duration(seconds: 2);
/// controller =
/// AnimationController.unbounded(duration: duration, vsync: this);
/// controller.repeat();
/// controller.addListener(() =>
/// print("Animation Controller value: ${controller.value}"));
/// }
/// ...
/// ```
mixin GetSingleTickerProviderStateMixin on GetxController
implements TickerProvider {
Ticker? _ticker;
@override
Ticker createTicker(TickerCallback onTick) {
assert(() {
if (_ticker == null) return true;
throw FlutterError.fromParts(<DiagnosticsNode>[
ErrorSummary(
'$runtimeType is a GetSingleTickerProviderStateMixin but multiple tickers were created.'),
ErrorDescription(
'A GetSingleTickerProviderStateMixin can only be used as a TickerProvider once.'),
ErrorHint(
'If a State is used for multiple AnimationController objects, or if it is passed to other '
'objects and those objects might use it more than one time in total, then instead of '
'mixing in a GetSingleTickerProviderStateMixin, use a regular GetTickerProviderStateMixin.',
),
]);
}());
_ticker =
Ticker(onTick, debugLabel: kDebugMode ? 'created by $this' : null);
// We assume that this is called from initState, build, or some sort of
// event handler, and that thus TickerMode.of(context) would return true. We
// can't actually check that here because if we're in initState then we're
// not allowed to do inheritance checks yet.
return _ticker!;
}
void didChangeDependencies(BuildContext context) {
if (_ticker != null) _ticker!.muted = !TickerMode.of(context);
}
@override
void onClose() {
assert(() {
if (_ticker == null || !_ticker!.isActive) return true;
throw FlutterError.fromParts(<DiagnosticsNode>[
ErrorSummary('$this was disposed with an active Ticker.'),
ErrorDescription(
'$runtimeType created a Ticker via its GetSingleTickerProviderStateMixin, but at the time '
'dispose() was called on the mixin, that Ticker was still active. The Ticker must '
'be disposed before calling super.dispose().',
),
ErrorHint(
'Tickers used by AnimationControllers '
'should be disposed by calling dispose() on the AnimationController itself. '
'Otherwise, the ticker will leak.',
),
_ticker!.describeForError('The offending ticker was'),
]);
}());
super.onClose();
}
}
/// Used like `TickerProviderMixin` but only with Get Controllers.
/// Simplifies multiple AnimationController creation inside GetxController.
///
/// Example:
///```
///class SplashController extends GetxController with
/// GetTickerProviderStateMixin {
/// AnimationController first_controller;
/// AnimationController second_controller;
///
/// @override
/// void onInit() {
/// final duration = const Duration(seconds: 2);
/// first_controller =
/// AnimationController.unbounded(duration: duration, vsync: this);
/// second_controller =
/// AnimationController.unbounded(duration: duration, vsync: this);
/// first_controller.repeat();
/// first_controller.addListener(() =>
/// print("Animation Controller value: ${first_controller.value}"));
/// second_controller.addListener(() =>
/// print("Animation Controller value: ${second_controller.value}"));
/// }
/// ...
/// ```
mixin GetTickerProviderStateMixin on GetxController implements TickerProvider {
Set<Ticker>? _tickers;
@override
Ticker createTicker(TickerCallback onTick) {
_tickers ??= <_WidgetTicker>{};
final result = _WidgetTicker(onTick, this,
debugLabel: kDebugMode ? 'created by ${describeIdentity(this)}' : null);
_tickers!.add(result);
return result;
}
void _removeTicker(_WidgetTicker ticker) {
assert(_tickers != null);
assert(_tickers!.contains(ticker));
_tickers!.remove(ticker);
}
void didChangeDependencies(BuildContext context) {
final muted = !TickerMode.of(context);
if (_tickers != null) {
for (final ticker in _tickers!) {
ticker.muted = muted;
}
}
}
@override
void onClose() {
assert(() {
if (_tickers != null) {
for (final ticker in _tickers!) {
if (ticker.isActive) {
throw FlutterError.fromParts(<DiagnosticsNode>[
ErrorSummary('$this was disposed with an active Ticker.'),
ErrorDescription(
'$runtimeType created a Ticker via its GetTickerProviderStateMixin, but at the time '
'dispose() was called on the mixin, that Ticker was still active. All Tickers must '
'be disposed before calling super.dispose().',
),
ErrorHint(
'Tickers used by AnimationControllers '
'should be disposed by calling dispose() on the AnimationController itself. '
'Otherwise, the ticker will leak.',
),
ticker.describeForError('The offending ticker was'),
]);
}
}
}
return true;
}());
super.onClose();
}
}
class _WidgetTicker extends Ticker {
_WidgetTicker(TickerCallback onTick, this._creator, {String? debugLabel})
: super(onTick, debugLabel: debugLabel);
final GetTickerProviderStateMixin _creator;
@override
void dispose() {
_creator._removeTicker(this);
super.dispose();
}
}
@Deprecated('use GetSingleTickerProviderStateMixin')
/// Used like `SingleTickerProviderMixin` but only with Get Controllers.
/// Simplifies AnimationController creation inside GetxController.
///
/// Example:
///```
///class SplashController extends GetxController with
/// SingleGetTickerProviderMixin {
/// AnimationController _ac;
///
/// @override
/// void onInit() {
/// final dur = const Duration(seconds: 2);
/// _ac = AnimationController.unbounded(duration: dur, vsync: this);
/// _ac.repeat();
/// _ac.addListener(() => print("Animation Controller value: ${_ac.value}"));
/// }
/// ...
/// ```
mixin SingleGetTickerProviderMixin on DisposableInterface
implements TickerProvider {
@override
Ticker createTicker(TickerCallback onTick) => Ticker(onTick);
}

View File

@@ -0,0 +1,123 @@
// ignore: prefer_mixin
import 'package:flutter/widgets.dart';
import '../../../instance_manager.dart';
import '../rx_flutter/rx_disposable.dart';
import '../rx_flutter/rx_notifier.dart';
import 'list_notifier.dart';
// ignore: prefer_mixin
abstract class GetxController extends DisposableInterface
with ListenableMixin, ListNotifierMixin {
/// Rebuilds `GetBuilder` each time you call `update()`;
/// Can take a List of [ids], that will only update the matching
/// `GetBuilder( id: )`,
/// [ids] can be reused among `GetBuilders` like group tags.
/// The update will only notify the Widgets, if [condition] is true.
void update([List<Object>? ids, bool condition = true]) {
if (!condition) {
return;
}
if (ids == null) {
refresh();
} else {
for (final id in ids) {
refreshGroup(id);
}
}
}
}
mixin ScrollMixin on GetLifeCycleBase {
final ScrollController scroll = ScrollController();
@override
void onInit() {
super.onInit();
scroll.addListener(_listener);
}
bool _canFetchBottom = true;
bool _canFetchTop = true;
void _listener() {
if (scroll.position.atEdge) {
_checkIfCanLoadMore();
}
}
Future<void> _checkIfCanLoadMore() async {
if (scroll.position.pixels == 0) {
if (!_canFetchTop) return;
_canFetchTop = false;
await onTopScroll();
_canFetchTop = true;
} else {
if (!_canFetchBottom) return;
_canFetchBottom = false;
await onEndScroll();
_canFetchBottom = true;
}
}
Future<void> onEndScroll();
Future<void> onTopScroll();
@override
void onClose() {
scroll.removeListener(_listener);
super.onClose();
}
}
abstract class RxController extends DisposableInterface {}
abstract class SuperController<T> extends FullLifeCycleController
with FullLifeCycleMixin, StateMixin<T> {}
abstract class FullLifeCycleController extends GetxController
with
// ignore: prefer_mixin
WidgetsBindingObserver {}
mixin FullLifeCycleMixin on FullLifeCycleController {
@mustCallSuper
@override
void onInit() {
super.onInit();
ambiguate(WidgetsBinding.instance)?.addObserver(this);
}
@mustCallSuper
@override
void onClose() {
ambiguate(WidgetsBinding.instance)?.removeObserver(this);
super.onClose();
}
@mustCallSuper
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
switch (state) {
case AppLifecycleState.resumed:
onResumed();
break;
case AppLifecycleState.inactive:
onInactive();
break;
case AppLifecycleState.paused:
onPaused();
break;
case AppLifecycleState.detached:
onDetached();
break;
}
}
void onResumed();
void onPaused();
void onInactive();
void onDetached();
}

View File

@@ -0,0 +1,172 @@
import 'package:flutter/widgets.dart';
import '../../../get.dart';
mixin GetResponsiveMixin on Widget {
ResponsiveScreen get screen;
bool get alwaysUseBuilder;
@protected
Widget build(BuildContext context) {
screen.context = context;
Widget? widget;
if (alwaysUseBuilder) {
widget = builder();
if (widget != null) return widget;
}
if (screen.isDesktop) {
widget = desktop() ?? widget;
if (widget != null) return widget;
}
if (screen.isTablet) {
widget = tablet() ?? desktop();
if (widget != null) return widget;
}
if (screen.isPhone) {
widget = phone() ?? tablet() ?? desktop();
if (widget != null) return widget;
}
return watch() ?? phone() ?? tablet() ?? desktop() ?? builder()!;
}
Widget? builder() => null;
Widget? desktop() => null;
Widget? phone() => null;
Widget? tablet() => null;
Widget? watch() => null;
}
/// Extend this widget to build responsive view.
/// this widget contains the `screen` property that have all
/// information about the screen size and type.
/// You have two options to build it.
/// 1- with `builder` method you return the widget to build.
/// 2- with methods `desktop`, `tablet`,`phone`, `watch`. the specific
/// method will be built when the screen type matches the method
/// when the screen is [ScreenType.Tablet] the `tablet` method
/// will be exuded and so on.
/// Note if you use this method please set the
/// property `alwaysUseBuilder` to false
/// With `settings` property you can set the width limit for the screen types.
class GetResponsiveView<T> extends GetView<T> with GetResponsiveMixin {
@override
final bool alwaysUseBuilder;
@override
final ResponsiveScreen screen;
GetResponsiveView({
this.alwaysUseBuilder = false,
ResponsiveScreenSettings settings = const ResponsiveScreenSettings(),
Key? key,
}) : screen = ResponsiveScreen(settings),
super(key: key);
}
class GetResponsiveWidget<T extends GetLifeCycleBase?> extends GetWidget<T>
with GetResponsiveMixin {
@override
final bool alwaysUseBuilder;
@override
final ResponsiveScreen screen;
GetResponsiveWidget({
this.alwaysUseBuilder = false,
ResponsiveScreenSettings settings = const ResponsiveScreenSettings(),
Key? key,
}) : screen = ResponsiveScreen(settings),
super(key: key);
}
class ResponsiveScreenSettings {
/// When the width is greater als this value
/// the display will be set as [ScreenType.Desktop]
final double desktopChangePoint;
/// When the width is greater als this value
/// the display will be set as [ScreenType.Tablet]
/// or when width greater als [watchChangePoint] and smaller als this value
/// the display will be [ScreenType.Phone]
final double tabletChangePoint;
/// When the width is smaller als this value
/// the display will be set as [ScreenType.Watch]
/// or when width greater als this value and smaller als [tabletChangePoint]
/// the display will be [ScreenType.Phone]
final double watchChangePoint;
const ResponsiveScreenSettings(
{this.desktopChangePoint = 1200,
this.tabletChangePoint = 600,
this.watchChangePoint = 300});
}
class ResponsiveScreen {
late BuildContext context;
final ResponsiveScreenSettings settings;
late bool _isPaltformDesktop;
ResponsiveScreen(this.settings) {
_isPaltformDesktop = GetPlatform.isDesktop;
}
double get height => context.height;
double get width => context.width;
/// Is [screenType] [ScreenType.Desktop]
bool get isDesktop => (screenType == ScreenType.Desktop);
/// Is [screenType] [ScreenType.Tablet]
bool get isTablet => (screenType == ScreenType.Tablet);
/// Is [screenType] [ScreenType.Phone]
bool get isPhone => (screenType == ScreenType.Phone);
/// Is [screenType] [ScreenType.Watch]
bool get isWatch => (screenType == ScreenType.Watch);
double get _getdeviceWidth {
if (_isPaltformDesktop) {
return width;
}
return context.mediaQueryShortestSide;
}
ScreenType get screenType {
final deviceWidth = _getdeviceWidth;
if (deviceWidth >= settings.desktopChangePoint) return ScreenType.Desktop;
if (deviceWidth >= settings.tabletChangePoint) return ScreenType.Tablet;
if (deviceWidth < settings.watchChangePoint) return ScreenType.Watch;
return ScreenType.Phone;
}
/// Return widget according to screen type
/// if the [screenType] is [ScreenType.Desktop] and
/// `desktop` object is null the `tablet` object will be returned
/// and if `tablet` object is null the `mobile` object will be returned
/// and if `mobile` object is null the `watch` object will be returned
/// also when it is null.
T? responsiveValue<T>({
T? mobile,
T? tablet,
T? desktop,
T? watch,
}) {
if (isDesktop && desktop != null) return desktop;
if (isTablet && tablet != null) return tablet;
if (isPhone && mobile != null) return mobile;
return watch;
}
}
enum ScreenType {
Watch,
Phone,
Tablet,
Desktop,
}

View File

@@ -0,0 +1,226 @@
import 'package:flutter/material.dart';
import '../../../get_instance/src/get_instance.dart';
import '../../../instance_manager.dart';
import '../../get_state_manager.dart';
import 'list_notifier.dart';
/// Complies with `GetStateUpdater`
///
/// This mixin's function represents a `GetStateUpdater`, and might be used
/// by `GetBuilder()`, `SimpleBuilder()` (or similar) to comply
/// with [GetStateUpdate] signature. REPLACING the [StateSetter].
/// Avoids the potential (but extremely unlikely) issue of having
/// the Widget in a dispose() state, and abstracts the
/// API from the ugly fn((){}).
mixin GetStateUpdaterMixin<T extends StatefulWidget> on State<T> {
// To avoid the creation of an anonym function to be GC later.
// ignore: prefer_function_declarations_over_variables
/// Experimental method to replace setState((){});
/// Used with GetStateUpdate.
void getUpdate() {
if (mounted) setState(() {});
}
}
typedef GetControllerBuilder<T extends DisposableInterface> = Widget Function(
T controller);
// class _InheritedGetxController<T extends GetxController>
// extends InheritedWidget {
// final T model;
// final int version;
// _InheritedGetxController({
// Key key,
// @required Widget child,
// @required this.model,
// }) : version = model.notifierVersion,
// super(key: key, child: child);
// @override
// bool updateShouldNotify(_InheritedGetxController<T> oldWidget) =>
// (oldWidget.version != version);
// }
// extension WatchEtx on GetxController {
// T watch<T extends GetxController>() {
// final instance = Get.find<T>();
// _GetBuilderState._currentState.watch(instance.update);
// return instance;
// }
// }
class GetBuilder<T extends GetxController> extends StatefulWidget {
final GetControllerBuilder<T> builder;
final bool global;
final Object? id;
final String? tag;
final bool autoRemove;
final bool assignId;
final Object Function(T value)? filter;
final void Function(GetBuilderState<T> state)? initState,
dispose,
didChangeDependencies;
final void Function(GetBuilder oldWidget, GetBuilderState<T> state)?
didUpdateWidget;
final T? init;
const GetBuilder({
Key? key,
this.init,
this.global = true,
required this.builder,
this.autoRemove = true,
this.assignId = false,
this.initState,
this.filter,
this.tag,
this.dispose,
this.id,
this.didChangeDependencies,
this.didUpdateWidget,
}) : super(key: key);
// static T of<T extends GetxController>(
// BuildContext context, {
// bool rebuild = false,
// }) {
// var widget = rebuild
// ? context
// .dependOnInheritedWidgetOfExactType<_InheritedGetxController<T>>()
// : context
// .getElementForInheritedWidgetOfExactType<
// _InheritedGetxController<T>>()
// ?.widget;
// if (widget == null) {
// throw 'Error: Could not find the correct dependency.';
// } else {
// return (widget as _InheritedGetxController<T>).model;
// }
// }
@override
GetBuilderState<T> createState() => GetBuilderState<T>();
}
class GetBuilderState<T extends GetxController> extends State<GetBuilder<T>>
with GetStateUpdaterMixin {
T? controller;
bool? _isCreator = false;
VoidCallback? _remove;
Object? _filter;
@override
void initState() {
// _GetBuilderState._currentState = this;
super.initState();
widget.initState?.call(this);
var isRegistered = GetInstance().isRegistered<T>(tag: widget.tag);
if (widget.global) {
if (isRegistered) {
if (GetInstance().isPrepared<T>(tag: widget.tag)) {
_isCreator = true;
} else {
_isCreator = false;
}
controller = GetInstance().find<T>(tag: widget.tag);
} else {
controller = widget.init;
_isCreator = true;
GetInstance().put<T>(controller!, tag: widget.tag);
}
} else {
controller = widget.init;
_isCreator = true;
controller?.onStart();
}
if (widget.filter != null) {
_filter = widget.filter!(controller!);
}
_subscribeToController();
}
/// Register to listen Controller's events.
/// It gets a reference to the remove() callback, to delete the
/// setState "link" from the Controller.
void _subscribeToController() {
_remove?.call();
_remove = (widget.id == null)
? controller?.addListener(
_filter != null ? _filterUpdate : getUpdate,
)
: controller?.addListenerId(
widget.id,
_filter != null ? _filterUpdate : getUpdate,
);
}
void _filterUpdate() {
var newFilter = widget.filter!(controller!);
if (newFilter != _filter) {
_filter = newFilter;
getUpdate();
}
}
@override
void dispose() {
super.dispose();
widget.dispose?.call(this);
if (_isCreator! || widget.assignId) {
if (widget.autoRemove && GetInstance().isRegistered<T>(tag: widget.tag)) {
GetInstance().delete<T>(tag: widget.tag);
}
}
_remove?.call();
controller = null;
_isCreator = null;
_remove = null;
_filter = null;
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
widget.didChangeDependencies?.call(this);
}
@override
void didUpdateWidget(GetBuilder oldWidget) {
super.didUpdateWidget(oldWidget as GetBuilder<T>);
// to avoid conflicts when modifying a "grouped" id list.
if (oldWidget.id != widget.id) {
_subscribeToController();
}
widget.didUpdateWidget?.call(oldWidget, this);
}
@override
Widget build(BuildContext context) {
// return _InheritedGetxController<T>(
// model: controller,
// child: widget.builder(controller),
// );
return widget.builder(controller!);
}
}
// extension FindExt on BuildContext {
// T find<T extends GetxController>() {
// return GetBuilder.of<T>(this, rebuild: false);
// }
// }
// extension ObserverEtx on BuildContext {
// T obs<T extends GetxController>() {
// return GetBuilder.of<T>(this, rebuild: true);
// }
// }

View File

@@ -0,0 +1,105 @@
import 'package:flutter/widgets.dart';
import '../../../instance_manager.dart';
import '../../../utils.dart';
import 'get_widget_cache.dart';
/// GetView is a great way of quickly access your Controller
/// without having to call Get.find<AwesomeController>() yourself.
///
/// Sample:
/// ```
/// class AwesomeController extends GetxController {
/// final String title = 'My Awesome View';
/// }
///
/// class AwesomeView extends GetView<AwesomeController> {
/// /// if you need you can pass the tag for
/// /// Get.find<AwesomeController>(tag:"myTag");
/// @override
/// final String tag = "myTag";
///
/// AwesomeView({Key key}):super(key:key);
///
/// @override
/// Widget build(BuildContext context) {
/// return Container(
/// padding: EdgeInsets.all(20),
/// child: Text( controller.title ),
/// );
/// }
/// }
///``
abstract class GetView<T> extends StatelessWidget {
const GetView({Key? key}) : super(key: key);
final String? tag = null;
T get controller => GetInstance().find<T>(tag: tag)!;
@override
Widget build(BuildContext context);
}
/// GetWidget is a great way of quickly access your individual Controller
/// without having to call Get.find<AwesomeController>() yourself.
/// Get save you controller on cache, so, you can to use Get.create() safely
/// GetWidget is perfect to multiples instance of a same controller. Each
/// GetWidget will have your own controller, and will be call events as `onInit`
/// and `onClose` when the controller get in/get out on memory.
abstract class GetWidget<S extends GetLifeCycleBase?> extends GetWidgetCache {
const GetWidget({Key? key}) : super(key: key);
@protected
final String? tag = null;
S get controller => GetWidget._cache[this] as S;
// static final _cache = <GetWidget, GetLifeCycleBase>{};
static final _cache = Expando<GetLifeCycleBase>();
@protected
Widget build(BuildContext context);
@override
WidgetCache createWidgetCache() => _GetCache<S>();
}
class _GetCache<S extends GetLifeCycleBase?> extends WidgetCache<GetWidget<S>> {
S? _controller;
bool _isCreator = false;
InstanceInfo? info;
@override
void onInit() {
info = GetInstance().getInstanceInfo<S>(tag: widget!.tag);
_isCreator = info!.isPrepared && info!.isCreate;
if (info!.isRegistered) {
_controller = Get.find<S>(tag: widget!.tag);
}
GetWidget._cache[widget!] = _controller;
super.onInit();
}
@override
void onClose() {
if (_isCreator) {
Get.asap(() {
widget!.controller!.onDelete();
Get.log('"${widget!.controller.runtimeType}" onClose() called');
Get.log('"${widget!.controller.runtimeType}" deleted from memory');
GetWidget._cache[widget!] = null;
});
}
info = null;
super.onClose();
}
@override
Widget build(BuildContext context) {
return widget!.build(context);
}
}

View File

@@ -0,0 +1,71 @@
import 'package:flutter/widgets.dart';
abstract class GetWidgetCache extends Widget {
const GetWidgetCache({Key? key}) : super(key: key);
@override
GetWidgetCacheElement createElement() => GetWidgetCacheElement(this);
@protected
@factory
WidgetCache createWidgetCache();
}
class GetWidgetCacheElement extends ComponentElement {
GetWidgetCacheElement(GetWidgetCache widget)
: cache = widget.createWidgetCache(),
super(widget) {
cache._element = this;
cache._widget = widget;
}
@override
void mount(Element? parent, dynamic newSlot) {
cache.onInit();
super.mount(parent, newSlot);
}
@override
Widget build() => cache.build(this);
final WidgetCache<GetWidgetCache> cache;
@override
void performRebuild() {
super.performRebuild();
}
@override
void activate() {
super.activate();
markNeedsBuild();
}
@override
void unmount() {
super.unmount();
cache.onClose();
cache._element = null;
}
}
@optionalTypeArgs
abstract class WidgetCache<T extends GetWidgetCache> {
T? get widget => _widget;
T? _widget;
BuildContext? get context => _element;
GetWidgetCacheElement? _element;
@protected
@mustCallSuper
void onInit() {}
@protected
@mustCallSuper
void onClose() {}
@protected
Widget build(BuildContext context);
}

View File

@@ -0,0 +1,175 @@
import 'dart:collection';
import 'package:flutter/widgets.dart';
// This callback remove the listener on addListener function
typedef Disposer = void Function();
// replacing StateSetter, return if the Widget is mounted for extra validation.
// if it brings overhead the extra call,
typedef GetStateUpdate = void Function();
class ListNotifier extends Listenable with ListenableMixin, ListNotifierMixin {}
mixin ListenableMixin implements Listenable {}
mixin ListNotifierMixin on ListenableMixin {
// int _version = 0;
// int _microtask = 0;
// int get notifierVersion => _version;
// int get notifierMicrotask => _microtask;
List<GetStateUpdate?>? _updaters = <GetStateUpdate?>[];
HashMap<Object?, List<GetStateUpdate>>? _updatersGroupIds =
HashMap<Object?, List<GetStateUpdate>>();
@protected
void refresh() {
assert(_debugAssertNotDisposed());
/// This debounce the call to update.
/// It prevent errors and duplicates builds
// if (_microtask == _version) {
// _microtask++;
// scheduleMicrotask(() {
// _version++;
// _microtask = _version;
_notifyUpdate();
// });
// }
}
void _notifyUpdate() {
for (var element in _updaters!) {
element!();
}
}
void _notifyIdUpdate(Object id) {
if (_updatersGroupIds!.containsKey(id)) {
final listGroup = _updatersGroupIds![id]!;
for (var item in listGroup) {
item();
}
}
}
@protected
void refreshGroup(Object id) {
assert(_debugAssertNotDisposed());
// /// This debounce the call to update.
// /// It prevent errors and duplicates builds
// if (_microtask == _version) {
// _microtask++;
// scheduleMicrotask(() {
// _version++;
// _microtask = _version;
_notifyIdUpdate(id);
// });
// }
}
bool _debugAssertNotDisposed() {
assert(() {
if (_updaters == null) {
throw FlutterError('''A $runtimeType was used after being disposed.\n
'Once you have called dispose() on a $runtimeType, it can no longer be used.''');
}
return true;
}());
return true;
}
@protected
void notifyChildrens() {
TaskManager.instance.notify(_updaters);
}
bool get hasListeners {
assert(_debugAssertNotDisposed());
return _updaters!.isNotEmpty;
}
int get listeners {
assert(_debugAssertNotDisposed());
return _updaters!.length;
}
@override
void removeListener(VoidCallback listener) {
assert(_debugAssertNotDisposed());
_updaters!.remove(listener);
}
void removeListenerId(Object id, VoidCallback listener) {
assert(_debugAssertNotDisposed());
if (_updatersGroupIds!.containsKey(id)) {
_updatersGroupIds![id]!.remove(listener);
}
_updaters!.remove(listener);
}
@mustCallSuper
void dispose() {
assert(_debugAssertNotDisposed());
_updaters = null;
_updatersGroupIds = null;
}
@override
Disposer addListener(GetStateUpdate listener) {
assert(_debugAssertNotDisposed());
_updaters!.add(listener);
return () => _updaters!.remove(listener);
}
Disposer addListenerId(Object? key, GetStateUpdate listener) {
_updatersGroupIds![key] ??= <GetStateUpdate>[];
_updatersGroupIds![key]!.add(listener);
return () => _updatersGroupIds![key]!.remove(listener);
}
/// To dispose an [id] from future updates(), this ids are registered
/// by `GetBuilder()` or similar, so is a way to unlink the state change with
/// the Widget from the Controller.
void disposeId(Object id) {
_updatersGroupIds!.remove(id);
}
}
class TaskManager {
TaskManager._();
static TaskManager? _instance;
static TaskManager get instance => _instance ??= TaskManager._();
GetStateUpdate? _setter;
List<VoidCallback>? _remove;
void notify(List<GetStateUpdate?>? _updaters) {
if (_setter != null) {
if (!_updaters!.contains(_setter)) {
_updaters.add(_setter);
_remove!.add(() => _updaters.remove(_setter));
}
}
}
Widget exchange(
List<VoidCallback> disposers,
GetStateUpdate setState,
Widget Function(BuildContext) builder,
BuildContext context,
) {
_remove = disposers;
_setter = setState;
final result = builder(context);
_remove = null;
_setter = null;
return result;
}
}

View File

@@ -0,0 +1,41 @@
import 'package:flutter/material.dart';
import '../../get_state_manager.dart';
class MixinBuilder<T extends GetxController> extends StatelessWidget {
@required
final Widget Function(T) builder;
final bool global;
final String? id;
final bool autoRemove;
final void Function(State state)? initState, dispose, didChangeDependencies;
final void Function(GetBuilder oldWidget, State state)? didUpdateWidget;
final T? init;
const MixinBuilder({
Key? key,
this.init,
this.global = true,
required this.builder,
this.autoRemove = true,
this.initState,
this.dispose,
this.id,
this.didChangeDependencies,
this.didUpdateWidget,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return GetBuilder<T>(
init: init,
global: global,
autoRemove: autoRemove,
initState: initState,
dispose: dispose,
id: id,
didChangeDependencies: didChangeDependencies,
didUpdateWidget: didUpdateWidget,
builder: (controller) => Obx(() => builder.call(controller)));
}
}

View File

@@ -0,0 +1,108 @@
import 'dart:async';
import 'package:flutter/widgets.dart';
import 'get_state.dart';
import 'list_notifier.dart';
typedef ValueBuilderUpdateCallback<T> = void Function(T snapshot);
typedef ValueBuilderBuilder<T> = Widget Function(
T snapshot, ValueBuilderUpdateCallback<T> updater);
/// Manages a local state like ObxValue, but uses a callback instead of
/// a Rx value.
///
/// Example:
/// ```
/// ValueBuilder<bool>(
/// initialValue: false,
/// builder: (value, update) => Switch(
/// value: value,
/// onChanged: (flag) {
/// update( flag );
/// },),
/// onUpdate: (value) => print("Value updated: $value"),
/// ),
/// ```
class ValueBuilder<T> extends StatefulWidget {
final T? initialValue;
final ValueBuilderBuilder<T> builder;
final void Function()? onDispose;
final void Function(T)? onUpdate;
const ValueBuilder({
Key? key,
this.initialValue,
this.onDispose,
this.onUpdate,
required this.builder,
}) : super(key: key);
@override
_ValueBuilderState<T> createState() => _ValueBuilderState<T>();
}
class _ValueBuilderState<T> extends State<ValueBuilder<T?>> {
T? value;
@override
void initState() {
super.initState();
value = widget.initialValue;
}
@override
Widget build(BuildContext context) => widget.builder(value, updater);
void updater(T? newValue) {
if (widget.onUpdate != null) {
widget.onUpdate!(newValue);
}
setState(() {
value = newValue;
});
}
@override
void dispose() {
super.dispose();
widget.onDispose?.call();
if (value is ChangeNotifier) {
(value as ChangeNotifier?)?.dispose();
} else if (value is StreamController) {
(value as StreamController?)?.close();
}
value = null;
}
}
// It's a experimental feature
class SimpleBuilder extends StatefulWidget {
final Widget Function(BuildContext) builder;
const SimpleBuilder({Key? key, required this.builder}) : super(key: key);
@override
_SimpleBuilderState createState() => _SimpleBuilderState();
}
class _SimpleBuilderState extends State<SimpleBuilder>
with GetStateUpdaterMixin {
final disposers = <Disposer>[];
@override
void dispose() {
super.dispose();
for (final disposer in disposers) {
disposer();
}
}
@override
Widget build(BuildContext context) {
return TaskManager.instance.exchange(
disposers,
getUpdate,
widget.builder,
context,
);
}
}