Jonny Borges

release candidate

Showing 71 changed files with 1324 additions and 1401 deletions
# Include option is buggy:
# https://github.com/flutter/flutter/issues/62591
include: package:lints/recommended.yaml
# In case the include issue gets fixed, lines below INCLUDE_FIX
# can be removed
# include: package:effective_dart/analysis_options.1.2.0.yaml
analyzer:
strong-mode:
implicit-casts: false
linter:
rules:
await_only_futures: true
# This one is desirable, but that's a lot of work for now
public_member_api_docs: false
# Desirable, but would be breaking changes:
avoid_positional_boolean_parameters: false
constant_identifier_names: false
include_file_not_found: false
# INCLUDE_FIX (copy of effective dart 1.2.0)
# STYLE
camel_case_types: true
close_sinks: true
unnecessary_statements: true
camel_case_extensions: true
library_names: true
file_names: true
library_prefixes: true
non_constant_identifier_names: true
directives_ordering: true
lines_longer_than_80_chars: true # avoid
curly_braces_in_flow_control_structures: true
# DOCUMENTATION
slash_for_doc_comments: true
package_api_docs: true # prefer
#- comment_references # Unused because https://github.com/dart-lang/sdk/issues/36974
# USAGE
implementation_imports: true
avoid_relative_lib_imports: true # prefer
prefer_relative_imports: true # prefer
prefer_adjacent_string_concatenation: true
prefer_interpolation_to_compose_strings: true # prefer
unnecessary_brace_in_string_interps: true # avoid
prefer_collection_literals: true
avoid_function_literals_in_foreach_calls: true # avoid
prefer_iterable_whereType: true
prefer_function_declarations_over_variables: true
unnecessary_lambdas: true
prefer_equal_for_default_values: true
avoid_init_to_null: true
unnecessary_getters_setters: true
annotate_overrides: true
#- unnecessary_getters # prefer # Disabled pending fix: https://github.com/dart-lang/linter/issues/23
#- prefer_expression_function_bodies # consider
unnecessary_this: true
prefer_initializing_formals: true
type_init_formals: true
empty_constructor_bodies: true
unnecessary_new: true
unnecessary_const: true
avoid_catches_without_on_clauses: true # avoid
avoid_catching_errors: true
use_rethrow_when_possible: true
unrelated_type_equality_checks: true
# DESIGN
use_to_and_as_if_applicable: true # prefer
one_member_abstracts: true # avoid
avoid_classes_with_only_static_members: true # avoid
prefer_mixin: true
prefer_final_fields: true # prefer
use_setters_to_change_properties: true
avoid_setters_without_getters: true
avoid_returning_null: true # avoid
avoid_returning_this: true # avoid
type_annotate_public_apis: true # prefer
#- prefer_typing_uninitialized_variables # consider
omit_local_variable_types: true # avoid
avoid_types_on_closure_parameters: true # avoid
avoid_return_types_on_setters: true # avoid
prefer_generic_function_type_aliases: true
avoid_private_typedef_functions: true # prefer
#- use_function_type_syntax_for_parameters # consider
hash_and_equals: true
avoid_equals_and_hash_code_on_mutable_classes: true # avoid
avoid_null_checks_in_equality_operators: true
... ...
... ... @@ -15,7 +15,7 @@ class AppPages {
GetPage(
name: Routes.HOME,
page: () => HomeView(),
bindings: [HomeBinding()],
binding: HomeBinding(),
children: [
GetPage(
name: Routes.COUNTRY,
... ...
... ... @@ -37,15 +37,22 @@ class MockRepositoryFailure implements IHomeRepository {
}
}
class MockBinding extends Binding {
@override
List<Bind> dependencies() {
return [
Bind.lazyPut<IHomeRepository>(() => MockRepositorySuccess()),
Bind.lazyPut<HomeController>(
() => HomeController(homeRepository: Get.find()),
)
];
}
}
void main() {
WidgetsFlutterBinding.ensureInitialized();
setUpAll(() => HttpOverrides.global = null);
final binding = BindingsBuilder(() {
Get.lazyPut<IHomeRepository>(() => MockRepositorySuccess());
Get.lazyPut<HomeController>(
() => HomeController(homeRepository: Get.find()),
);
});
final binding = MockBinding();
test('Test Controller', () async {
/// Controller can't be on memory
... ... @@ -53,7 +60,7 @@ void main() {
throwsA(m.TypeMatcher<String>()));
/// binding will put the controller on memory
binding.builder();
binding.dependencies();
/// recover your controller
final controller = Get.find<HomeController>();
... ...
... ... @@ -9,22 +9,22 @@ class HomeView extends GetView<HomeController> {
@override
Widget build(BuildContext context) {
return GetRouterOutlet.builder(
routerDelegate: Get.nestedKey(Routes.HOME),
routerDelegate: Get.nestedKey(Routes.home),
builder: (context) {
final delegate = context.navigation;
//This router outlet handles the appbar and the bottom navigation bar
final currentLocation = context.location;
var currentIndex = 0;
if (currentLocation.startsWith(Routes.PRODUCTS) == true) {
if (currentLocation.startsWith(Routes.products) == true) {
currentIndex = 2;
}
if (currentLocation.startsWith(Routes.PROFILE) == true) {
if (currentLocation.startsWith(Routes.profile) == true) {
currentIndex = 1;
}
return Scaffold(
body: GetRouterOutlet(
initialRoute: Routes.DASHBOARD,
anchorRoute: Routes.HOME,
initialRoute: Routes.dashboard,
anchorRoute: Routes.home,
//delegate: Get.nestedKey(Routes.HOME),
// key: Get.nestedKey(Routes.HOME),
... ... @@ -34,13 +34,13 @@ class HomeView extends GetView<HomeController> {
onTap: (value) {
switch (value) {
case 0:
delegate.toNamed(Routes.HOME);
delegate.toNamed(Routes.home);
break;
case 1:
delegate.toNamed(Routes.PROFILE);
delegate.toNamed(Routes.profile);
break;
case 2:
delegate.toNamed(Routes.PRODUCTS);
delegate.toNamed(Routes.products);
break;
default:
}
... ...
... ... @@ -32,7 +32,7 @@ class LoginView extends GetView<LoginController> {
onPressed: () {
AuthService.to.login();
final thenTo = context.params['then'];
Get.offNamed(thenTo ?? Routes.HOME);
Get.offNamed(thenTo ?? Routes.home);
},
),
],
... ...
... ... @@ -39,7 +39,7 @@ class ProfileView extends GetView<ProfileController> {
Get.defaultDialog(
title: 'Test Dialog In Home Outlet !!',
barrierDismissible: true,
id: Routes.HOME,
id: Routes.home,
// navigatorKey: Get.nestedKey(Routes.HOME),
);
},
... ...
import 'package:get/get.dart';
class RootController extends GetxController {
//TODO: Implement RootController
final count = 0.obs;
@override
void onInit() {
super.onInit();
}
@override
void onReady() {
super.onReady();
}
@override
void onClose() {}
... ...
... ... @@ -21,7 +21,7 @@ class DrawerWidget extends StatelessWidget {
ListTile(
title: Text('Home'),
onTap: () {
Get.toNamed(Routes.HOME);
Get.toNamed(Routes.home);
//to close the drawer
Navigator.of(context).pop();
... ... @@ -30,7 +30,7 @@ class DrawerWidget extends StatelessWidget {
ListTile(
title: Text('Settings'),
onTap: () {
Get.toNamed(Routes.SETTINGS);
Get.toNamed(Routes.settings);
//to close the drawer
Navigator.of(context).pop();
... ... @@ -46,7 +46,7 @@ class DrawerWidget extends StatelessWidget {
),
onTap: () {
AuthService.to.logout();
Get.toNamed(Routes.LOGIN);
Get.toNamed(Routes.login);
//to close the drawer
Navigator.of(context).pop();
... ... @@ -61,7 +61,7 @@ class DrawerWidget extends StatelessWidget {
),
),
onTap: () {
Get.toNamed(Routes.LOGIN);
Get.toNamed(Routes.login);
//to close the drawer
Navigator.of(context).pop();
... ...
... ... @@ -21,7 +21,7 @@ class RootView extends GetView<RootController> {
//body: HomeView(),
body: GetRouterOutlet(
initialRoute: Routes.HOME,
initialRoute: Routes.home,
delegate: Get.nestedKey(null),
anchorRoute: '/',
filterPages: (afterAnchor) {
... ...
import 'package:get/get.dart';
class SettingsController extends GetxController {
//TODO: Implement SettingsController
final count = 0.obs;
@override
void onInit() {
super.onInit();
}
@override
void onReady() {
super.onReady();
}
@override
void onClose() {}
... ...
... ... @@ -23,7 +23,7 @@ part 'app_routes.dart';
class AppPages {
AppPages._();
static const INITIAL = Routes.HOME;
static const initial = Routes.home;
static final routes = [
GetPage(
... ... @@ -38,13 +38,13 @@ class AppPages {
//only enter this route when not authed
EnsureNotAuthedMiddleware(),
],
name: _Paths.LOGIN,
name: _Paths.login,
page: () => LoginView(),
bindings: [LoginBinding()],
),
GetPage(
preventDuplicates: true,
name: _Paths.HOME,
name: _Paths.home,
page: () => const HomeView(),
bindings: [
HomeBinding(),
... ... @@ -52,7 +52,7 @@ class AppPages {
title: null,
children: [
GetPage(
name: _Paths.DASHBOARD,
name: _Paths.dashboard,
page: () => DashboardView(),
bindings: [
DashboardBinding(),
... ... @@ -63,14 +63,14 @@ class AppPages {
//only enter this route when authed
EnsureAuthMiddleware(),
],
name: _Paths.PROFILE,
name: _Paths.profile,
page: () => ProfileView(),
title: 'Profile',
transition: Transition.size,
bindings: [ProfileBinding()],
),
GetPage(
name: _Paths.PRODUCTS,
name: _Paths.products,
page: () => const ProductsView(),
title: 'Products',
transition: Transition.zoom,
... ... @@ -78,7 +78,7 @@ class AppPages {
bindings: [ProductsBinding()],
children: [
GetPage(
name: _Paths.PRODUCT_DETAILS,
name: _Paths.productDetails,
page: () => ProductDetailsView(),
bindings: [ProductDetailsBinding()],
middlewares: [
... ... @@ -91,7 +91,7 @@ class AppPages {
],
),
GetPage(
name: _Paths.SETTINGS,
name: _Paths.settings,
page: () => SettingsView(),
bindings: [
SettingsBinding(),
... ...
... ... @@ -4,27 +4,27 @@ part of 'app_pages.dart';
// DO NOT EDIT. This is code generated via package:get_cli/get_cli.dart
abstract class Routes {
static const HOME = _Paths.HOME;
static const home = _Paths.home;
static const PROFILE = _Paths.HOME + _Paths.PROFILE;
static const SETTINGS = _Paths.SETTINGS;
static const profile = _Paths.home + _Paths.profile;
static const settings = _Paths.settings;
static const PRODUCTS = _Paths.HOME + _Paths.PRODUCTS;
static const products = _Paths.home + _Paths.products;
static const LOGIN = _Paths.LOGIN;
static const DASHBOARD = _Paths.HOME + _Paths.DASHBOARD;
static const login = _Paths.login;
static const dashboard = _Paths.home + _Paths.dashboard;
Routes._();
static String LOGIN_THEN(String afterSuccessfulLogin) =>
'$LOGIN?then=${Uri.encodeQueryComponent(afterSuccessfulLogin)}';
static String PRODUCT_DETAILS(String productId) => '$PRODUCTS/$productId';
'$login?then=${Uri.encodeQueryComponent(afterSuccessfulLogin)}';
static String PRODUCT_DETAILS(String productId) => '$products/$productId';
}
abstract class _Paths {
static const HOME = '/home';
static const PRODUCTS = '/products';
static const PROFILE = '/profile';
static const SETTINGS = '/settings';
static const PRODUCT_DETAILS = '/:productId';
static const LOGIN = '/login';
static const DASHBOARD = '/dashboard';
static const home = '/home';
static const products = '/products';
static const profile = '/profile';
static const settings = '/settings';
static const productDetails = '/:productId';
static const login = '/login';
static const dashboard = '/dashboard';
}
... ...
... ... @@ -9,14 +9,12 @@ void main() {
runApp(
GetMaterialApp(
title: "Application",
initialBinding: BindingsBuilder(
() {
Get.put(SplashService());
Get.put(AuthService());
},
),
binds: [
Bind.put(SplashService()),
Bind.put(AuthService()),
],
getPages: AppPages.routes,
initialRoute: AppPages.INITIAL,
initialRoute: AppPages.initial,
// builder: (context, child) {
// return FutureBuilder<void>(
// key: ValueKey('initFuture'),
... ...
import '../get.dart';
extension GetResetExt on GetInterface {
void reset(
{@deprecated bool clearFactory = true, bool clearRouteBindings = true}) {
GetInstance().resetInstance(clearRouteBindings: clearRouteBindings);
Get.clearRouteTree();
void reset({bool clearRouteBindings = true}) {
Get.resetInstance(clearRouteBindings: clearRouteBindings);
// Get.clearRouteTree();
Get.clearTranslations();
Get.resetRootNavigator();
// Get.resetRootNavigator();
}
}
... ...
class TrustedCertificate {
final List<int> bytes;
TrustedCertificate(this.bytes);
const TrustedCertificate(this.bytes);
}
... ...
... ... @@ -8,9 +8,7 @@ import '../src/request/request.dart';
import '../src/response/response.dart';
import '../src/status/http_status.dart';
import 'http/interface/request_base.dart';
import 'http/stub/http_request_stub.dart'
if (dart.library.html) 'http/html/http_request_html.dart'
if (dart.library.io) 'http/io/http_request_io.dart';
import 'http/request/http_request.dart';
import 'interceptors/get_modifiers.dart';
typedef Decoder<T> = T Function(dynamic data);
... ... @@ -55,7 +53,7 @@ class GetHttpClient {
List<TrustedCertificate>? trustedCertificates,
bool withCredentials = false,
String Function(Uri url)? findProxy,
}) : _httpClient = HttpRequestImpl(
}) : _httpClient = createHttp(
allowAutoSignedCert: allowAutoSignedCert,
trustedCertificates: trustedCertificates,
withCredentials: withCredentials,
... ...
import 'dart:async';
import 'dart:html' as html;
import 'dart:html';
import '../../certificates/certificates.dart';
import '../../exceptions/exceptions.dart';
... ... @@ -18,7 +18,7 @@ class HttpRequestImpl implements HttpRequestBase {
});
/// The currently active XHRs.
final _xhrs = <html.HttpRequest>{};
final _xhrs = <HttpRequest>{};
///This option requires that you submit credentials for requests
///on different sites. The default is false
... ... @@ -31,9 +31,9 @@ class HttpRequestImpl implements HttpRequestBase {
@override
Future<Response<T>> send<T>(Request<T> request) async {
var bytes = await request.bodyBytes.toBytes();
html.HttpRequest xhr;
HttpRequest xhr;
xhr = html.HttpRequest()
xhr = HttpRequest()
..timeout = timeout?.inMilliseconds
..open(request.method, '${request.url}', async: true); // check this
... ... @@ -46,8 +46,8 @@ class HttpRequestImpl implements HttpRequestBase {
var completer = Completer<Response<T>>();
xhr.onLoad.first.then((_) {
var blob = xhr.response as html.Blob? ?? html.Blob([]);
var reader = html.FileReader();
var blob = xhr.response as Blob? ?? Blob([]);
var reader = FileReader();
reader.onLoad.first.then((_) async {
var bodyBytes = BodyBytesStream.fromBytes(reader.result as List<int>);
... ...
import '../../certificates/certificates.dart';
import '../stub/http_request_stub.dart'
if (dart.library.html) '../html/http_request_html.dart'
if (dart.library.io) '../io/http_request_io.dart';
HttpRequestImpl createHttp({
bool allowAutoSignedCert = true,
List<TrustedCertificate>? trustedCertificates,
bool withCredentials = false,
String Function(Uri url)? findProxy,
}) {
return HttpRequestImpl(
allowAutoSignedCert: allowAutoSignedCert,
trustedCertificates: trustedCertificates,
withCredentials: withCredentials,
findProxy: findProxy,
);
}
... ...
import 'dart:convert';
import '../../../../../get_core/get_core.dart';
import '../../request/request.dart';
T? bodyDecoded<T>(Request<T> request, String stringBody, String? mimeType) {
T? body;
var bodyToDecode;
dynamic bodyToDecode;
if (mimeType != null && mimeType.contains('application/json')) {
try {
... ...
... ... @@ -10,7 +10,7 @@ typedef ResponseModifier<T> = FutureOr Function(
typedef HandlerExecute<T> = Future<Request<T>> Function();
class GetModifier<T> {
class GetModifier<S> {
final _requestModifiers = <RequestModifier>[];
final _responseModifiers = <ResponseModifier>[];
RequestModifier? authenticator;
... ...
import 'dart:async';
import 'dart:convert';
import 'dart:math';
import '../request/request.dart';
import '../utils/utils.dart';
import 'multipart_file.dart';
... ... @@ -8,7 +9,7 @@ import 'multipart_file.dart';
class FormData {
FormData(Map<String, dynamic> map) : boundary = _getBoundary() {
map.forEach((key, value) {
if (value == null) return null;
if (value == null) return;
if (value is MultipartFile) {
files.add(MapEntry(key, value));
} else if (value is List<MultipartFile>) {
... ...
import 'dart:collection';
import 'dart:convert';
import '../exceptions/exceptions.dart';
import '../request/request.dart';
import '../status/http_status.dart';
... ... @@ -206,7 +207,7 @@ class HeaderValue {
}
String? parseParameterValue() {
if (!done() && value[index] == '\"') {
if (!done() && value[index] == '"') {
var stringBuffer = StringBuffer();
index++;
while (!done()) {
... ... @@ -214,11 +215,11 @@ class HeaderValue {
if (index + 1 == value.length) {
throw StateError('Failed to parse header value');
}
if (preserveBackslash && value[index + 1] != '\"') {
if (preserveBackslash && value[index + 1] != '"') {
stringBuffer.write(value[index]);
}
index++;
} else if (value[index] == '\"') {
} else if (value[index] == '"') {
index++;
break;
}
... ...
// ignore_for_file: constant_identifier_names
import 'dart:convert';
bool isTokenChar(int byte) {
... ...
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'log.dart';
import 'smart_management.dart';
... ... @@ -8,8 +7,6 @@ import 'smart_management.dart';
/// class through extensions
abstract class GetInterface {
SmartManagement smartManagement = SmartManagement.full;
RouterDelegate? routerDelegate;
RouteInformationParser? routeInformationParser;
bool isLogEnable = kDebugMode;
LogWriterCallback log = defaultLogWriterCallback;
}
... ...
export 'src/bindings_interface.dart';
export 'src/extension_instance.dart';
export 'src/get_instance.dart';
export 'src/lifecycle.dart';
... ...
// ignore: one_member_abstracts
import 'get_instance.dart';
// ignore: one_member_abstracts
abstract class BindingsInterface<T> {
... ... @@ -18,52 +17,52 @@ abstract class Bindings extends BindingsInterface<void> {
void dependencies();
}
/// Simplifies Bindings generation from a single callback.
/// To avoid the creation of a custom Binding instance per route.
///
/// Example:
/// ```
/// GetPage(
/// name: '/',
/// page: () => Home(),
/// // This might cause you an error.
/// // binding: BindingsBuilder(() => Get.put(HomeController())),
/// binding: BindingsBuilder(() { Get.put(HomeController(); })),
/// // Using .lazyPut() works fine.
/// // binding: BindingsBuilder(() => Get.lazyPut(() => HomeController())),
/// ),
/// ```
class BindingsBuilder<T> extends Bindings {
/// Register your dependencies in the [builder] callback.
final BindingBuilderCallback builder;
// /// Simplifies Bindings generation from a single callback.
// /// To avoid the creation of a custom Binding instance per route.
// ///
// /// Example:
// /// ```
// /// GetPage(
// /// name: '/',
// /// page: () => Home(),
// /// // This might cause you an error.
// /// // binding: BindingsBuilder(() => Get.put(HomeController())),
// /// binding: BindingsBuilder(() { Get.put(HomeController(); })),
// /// // Using .lazyPut() works fine.
// /// // binding: BindingsBuilder(() => Get.lazyPut(() => HomeController())),
// /// ),
// /// ```
// class BindingsBuilder<T> extends Bindings {
// /// Register your dependencies in the [builder] callback.
// final BindingBuilderCallback builder;
/// Shortcut to register 1 Controller with Get.put(),
/// Prevents the issue of the fat arrow function with the constructor.
/// BindingsBuilder(() => Get.put(HomeController())),
///
/// Sample:
/// ```
/// GetPage(
/// name: '/',
/// page: () => Home(),
/// binding: BindingsBuilder.put(() => HomeController()),
/// ),
/// ```
factory BindingsBuilder.put(InstanceBuilderCallback<T> builder,
{String? tag, bool permanent = false}) {
return BindingsBuilder(
() => GetInstance().put<T>(builder(), tag: tag, permanent: permanent));
}
// /// Shortcut to register 1 Controller with Get.put(),
// /// Prevents the issue of the fat arrow function with the constructor.
// /// BindingsBuilder(() => Get.put(HomeController())),
// ///
// /// Sample:
// /// ```
// /// GetPage(
// /// name: '/',
// /// page: () => Home(),
// /// binding: BindingsBuilder.put(() => HomeController()),
// /// ),
// /// ```
// factory BindingsBuilder.put(InstanceBuilderCallback<T> builder,
// {String? tag, bool permanent = false}) {
// return BindingsBuilder(
// () => Get.put<T>(builder(), tag: tag, permanent: permanent));
// }
/// WARNING: don't use `()=> Get.put(Controller())`,
/// if only passing 1 callback use `BindingsBuilder.put(Controller())`
/// or `BindingsBuilder(()=> Get.lazyPut(Controller()))`
BindingsBuilder(this.builder);
// /// WARNING: don't use `()=> Get.put(Controller())`,
// /// if only passing 1 callback use `BindingsBuilder.put(Controller())`
// /// or `BindingsBuilder(()=> Get.lazyPut(Controller()))`
// BindingsBuilder(this.builder);
@override
void dependencies() {
builder();
}
}
// @override
// void dependencies() {
// builder();
// }
// }
typedef BindingBuilderCallback = void Function();
... ...
import '../../route_manager.dart';
import 'get_instance.dart';
import 'dart:async';
import '../../get_core/get_core.dart';
import '../../get_navigation/src/router_report.dart';
import 'lifecycle.dart';
class InstanceInfo {
final bool? isPermanent;
final bool? isSingleton;
bool get isCreate => !isSingleton!;
final bool isRegistered;
final bool isPrepared;
final bool? isInit;
const InstanceInfo({
required this.isPermanent,
required this.isSingleton,
required this.isRegistered,
required this.isPrepared,
required this.isInit,
});
}
extension Inst on GetInterface {
T call<T>() => find<T>();
/// Holds references to every registered Instance when using
/// `Get.put()`
static final Map<String, _InstanceBuilderFactory> _singl = {};
/// Holds a reference to every registered callback when using
/// `Get.lazyPut()`
// static final Map<String, _Lazy> _factory = {};
// void injector<S>(
// InjectorBuilderCallback<S> fn, {
// String? tag,
// bool fenix = false,
// // bool permanent = false,
// }) {
// lazyPut(
// () => fn(this),
// tag: tag,
// fenix: fenix,
// // permanent: permanent,
// );
// }
/// async version of `Get.put()`.
/// Awaits for the resolution of the Future from `builder()` parameter and
/// stores the Instance returned.
Future<S> putAsync<S>(
AsyncInstanceBuilderCallback<S> builder, {
String? tag,
bool permanent = false,
}) async {
return put<S>(await builder(), tag: tag, permanent: permanent);
}
/// Injects an instance `<S>` in memory to be globally accessible.
///
/// No need to define the generic type `<S>` as it's inferred from
/// the [dependency]
///
/// - [dependency] The Instance to be injected.
/// - [tag] optionally, use a [tag] as an "id" to create multiple records of
/// the same Type<[S]>
/// - [permanent] keeps the Instance in memory, not following
/// `Get.smartManagement` rules.
S put<S>(
S dependency, {
String? tag,
bool permanent = false,
}) {
_insert(
isSingleton: true,
name: tag,
permanent: permanent,
builder: (() => dependency));
return find<S>(tag: tag);
}
/// Creates a new Instance<S> lazily from the `<S>builder()` callback.
///
/// The first time you call `Get.find()`, the `builder()` callback will create
/// the Instance and persisted as a Singleton (like you would use
/// `Get.put()`).
/// the Instance and persisted as a Singleton (like you would
/// use `Get.put()`).
///
/// Using `Get.smartManagement` as [SmartManagement.keepFactory] has
/// the same outcome
/// as using `fenix:true` :
/// the same outcome as using `fenix:true` :
/// The internal register of `builder()` will remain in memory to recreate
/// the Instance if the Instance has been removed with `Get.delete()`.
/// Therefore, future calls to `Get.find()` will return the same Instance.
///
/// If you need to make use of GetxController's life-cycle
/// (`onInit(), onStart(), onClose()`)
/// [fenix] is a great choice to mix with `GetBuilder` and `GetX` widgets,
/// and/or [GetMaterialApp] Navigation.
/// (`onInit(), onStart(), onClose()`) [fenix] is a great choice to mix with
/// `GetBuilder()` and `GetX()` widgets, and/or `GetMaterialApp` Navigation.
///
/// You could use `Get.lazyPut(fenix:true)` in your app's `main()` instead of
/// `Bindings` for each [GetPage].
/// You could use `Get.lazyPut(fenix:true)` in your app's `main()` instead
/// of `Bindings()` for each `GetPage`.
/// And the memory management will be similar.
///
/// Subsequent calls to `Get.lazyPut` with the same parameters
/// (`<S>` and optionally [tag] will **not** override the original).
void lazyPut<S>(InstanceBuilderCallback<S> builder,
{String? tag, bool fenix = false}) {
GetInstance().lazyPut<S>(builder, tag: tag, fenix: fenix);
/// Subsequent calls to `Get.lazyPut()` with the same parameters
/// (<[S]> and optionally [tag] will **not** override the original).
void lazyPut<S>(
InstanceBuilderCallback<S> builder, {
String? tag,
bool? fenix,
bool permanent = false,
}) {
_insert(
isSingleton: true,
name: tag,
permanent: permanent,
builder: builder,
fenix: fenix ?? Get.smartManagement == SmartManagement.keepFactory,
);
}
// void printInstanceStack() {
// GetInstance().printInstanceStack();
// }
/// async version of `Get.put()`.
/// Awaits for the resolution of the Future from `builder()`parameter and
/// stores the Instance returned.
Future<S> putAsync<S>(AsyncInstanceBuilderCallback<S> builder,
{String? tag, bool permanent = false}) async =>
GetInstance().putAsync<S>(builder, tag: tag, permanent: permanent);
/// Creates a new Class Instance [S] from the builder callback[S].
/// Every time `find<S>()` is used, it calls the builder method to generate
/// Every time [find]<[S]>() is used, it calls the builder method to generate
/// a new Instance [S].
/// It also registers each `instance.onClose()` with the current
/// Route `GetConfig.currentRoute` to keep the lifecycle active.
/// Route `Get.reference` to keep the lifecycle active.
/// Is important to know that the instances created are only stored per Route.
/// So, if you call `Get.delete<T>()` the "instance factory" used in this
/// method (`Get.create<T>()`) will be removed, but NOT the instances
/// already created by it.
/// Uses `tag` as the other methods.
///
/// Example:
///
... ... @@ -59,85 +132,169 @@ extension Inst on GetInterface {
/// Repl a = find();
/// Repl b = find();
/// print(a==b); (false)```
void create<S>(InstanceBuilderCallback<S> builder,
{String? tag, bool permanent = true}) =>
GetInstance().create<S>(builder, tag: tag, permanent: permanent);
/// Finds a Instance of the required Class `<S>`(or [tag])
/// In the case of using `Get.create()`, it will generate an Instance
/// each time you call `Get.find()`.
S find<S>({String? tag}) => GetInstance().find<S>(tag: tag);
void create<S>(
InstanceBuilderCallback<S> builder, {
String? tag,
bool permanent = true,
}) {
_insert(
isSingleton: false,
name: tag,
builder: builder,
permanent: permanent,
);
}
/// Injects an `Instance<S>` in memory.
///
/// No need to define the generic type `<[S]>` as it's inferred
/// from the [dependency] parameter.
///
/// - [dependency] The Instance to be injected.
/// - [tag] optionally, use a [tag] as an "id" to create multiple records
/// of the same `Type<S>` the [tag] does **not** conflict with the same tags
/// used by other dependencies Types.
/// - [permanent] keeps the Instance in memory and persist it,
/// not following `Get.smartManagement`
/// rules. Although, can be removed by `GetInstance.reset()`
/// and `Get.delete()`
/// - [builder] If defined, the [dependency] must be returned from here
S put<S>(S dependency,
{String? tag,
/// Injects the Instance [S] builder into the `_singleton` HashMap.
void _insert<S>({
bool? isSingleton,
String? name,
bool permanent = false,
InstanceBuilderCallback<S>? builder}) =>
GetInstance().put<S>(dependency, tag: tag, permanent: permanent);
required InstanceBuilderCallback<S> builder,
bool fenix = false,
}) {
final key = _getKey(S, name);
/// Clears all registered instances (and/or tags).
/// Even the persistent ones.
///
/// - `clearFactory` clears the callbacks registered by `Get.lazyPut()`
/// - `clearRouteBindings` clears Instances associated with Routes when using
/// [GetMaterialApp].
// bool reset(
// {@deprecated bool clearFactory = true,
// @deprecated bool clearRouteBindings = true}) =>
// GetInstance().reset(
// // ignore: deprecated_member_use_from_same_package
// clearFactory: clearFactory,
// // ignore: deprecated_member_use_from_same_package
// clearRouteBindings: clearRouteBindings);
/// Deletes the `Instance<S>`, cleaning the memory and closes any open
/// controllers (`DisposableInterface`).
///
/// - [tag] Optional "tag" used to register the Instance
/// - [force] Will delete an Instance even if marked as `permanent`.
Future<bool> delete<S>({String? tag, bool force = false}) async =>
GetInstance().delete<S>(tag: tag, force: force);
_InstanceBuilderFactory<S>? dep;
if (_singl.containsKey(key)) {
final _dep = _singl[key];
if (_dep == null || !_dep.isDirty) {
return;
} else {
dep = _dep as _InstanceBuilderFactory<S>;
}
}
_singl[key] = _InstanceBuilderFactory<S>(
isSingleton: isSingleton,
builderFunc: builder,
permanent: permanent,
isInit: false,
fenix: fenix,
tag: name,
lateRemove: dep,
);
}
/// Deletes all Instances, cleaning the memory and closes any open
/// controllers (`DisposableInterface`).
///
/// - [force] Will delete the Instances even if marked as `permanent`.
Future<void> deleteAll({bool force = false}) async =>
GetInstance().deleteAll(force: force);
/// Initializes the dependencies for a Class Instance [S] (or tag),
/// If its a Controller, it starts the lifecycle process.
/// Optionally associating the current Route to the lifetime of the instance,
/// if `Get.smartManagement` is marked as [SmartManagement.full] or
/// [SmartManagement.keepFactory]
/// Only flags `isInit` if it's using `Get.create()`
/// (not for Singletons access).
/// Returns the instance if not initialized, required for Get.create() to
/// work properly.
S? _initDependencies<S>({String? name}) {
final key = _getKey(S, name);
final isInit = _singl[key]!.isInit;
S? i;
if (!isInit) {
i = _startController<S>(tag: name);
if (_singl[key]!.isSingleton!) {
_singl[key]!.isInit = true;
if (Get.smartManagement != SmartManagement.onlyBuilder) {
RouterReportManager.instance
.reportDependencyLinkedToRoute(_getKey(S, name));
}
}
}
return i;
}
void reloadAll({bool force = false}) => GetInstance().reloadAll(force: force);
InstanceInfo getInstanceInfo<S>({String? tag}) {
final build = _getDependency<S>(tag: tag);
void reload<S>({String? tag, String? key, bool force = false}) =>
GetInstance().reload<S>(tag: tag, key: key, force: force);
return InstanceInfo(
isPermanent: build?.permanent,
isSingleton: build?.isSingleton,
isRegistered: isRegistered<S>(tag: tag),
isPrepared: !(build?.isInit ?? true),
isInit: build?.isInit,
);
}
/// Checks if a Class `Instance<S>` (or [tag]) is registered in memory.
/// - [tag] optional, if you use a [tag] to register the Instance.
bool isRegistered<S>({String? tag}) =>
GetInstance().isRegistered<S>(tag: tag);
_InstanceBuilderFactory? _getDependency<S>({String? tag, String? key}) {
final newKey = key ?? _getKey(S, tag);
/// Checks if an `Instance<S>` (or [tag]) returned from a factory builder
/// `Get.lazyPut()`, is registered in memory.
/// - [tag] optional, if you use a [tag] to register the Instance.
bool isPrepared<S>({String? tag}) => GetInstance().isPrepared<S>(tag: tag);
if (!_singl.containsKey(newKey)) {
Get.log('Instance "$newKey" is not registered.', isError: true);
return null;
} else {
return _singl[newKey];
}
}
void markAsDirty<S>({String? tag, String? key}) {
final newKey = key ?? _getKey(S, tag);
if (_singl.containsKey(newKey)) {
final dep = _singl[newKey];
if (dep != null && !dep.permanent) {
dep.isDirty = true;
}
}
}
/// Initializes the controller
S _startController<S>({String? tag}) {
final key = _getKey(S, tag);
final i = _singl[key]!.getDependency() as S;
if (i is GetLifeCycleMixin) {
i.onStart();
if (tag == null) {
Get.log('Instance "$S" has been initialized');
} else {
Get.log('Instance "$S" with tag "$tag" has been initialized');
}
if (!_singl[key]!.isSingleton!) {
RouterReportManager.instance.appendRouteByCreate(i);
}
}
return i;
}
S putOrFind<S>(InstanceBuilderCallback<S> dep, {String? tag}) {
final key = _getKey(S, tag);
if (_singl.containsKey(key)) {
return _singl[key]!.getDependency() as S;
} else {
return put(dep(), tag: tag);
}
}
/// Finds the registered type <[S]> (or [tag])
/// In case of using Get.[create] to register a type <[S]> or [tag],
/// it will create an instance each time you call [find].
/// If the registered type <[S]> (or [tag]) is a Controller,
/// it will initialize it's lifecycle.
S find<S>({String? tag}) {
final key = _getKey(S, tag);
if (isRegistered<S>(tag: tag)) {
final dep = _singl[key];
if (dep == null) {
if (tag == null) {
throw 'Class "$S" is not registered';
} else {
throw 'Class "$S" with tag "$tag" is not registered';
}
}
/// although dirty solution, the lifecycle starts inside
/// `initDependencies`, so we have to return the instance from there
/// to make it compatible with `Get.create()`.
final i = _initDependencies<S>(name: tag);
return i ?? dep.getDependency() as S;
} else {
// ignore: lines_longer_than_80_chars
throw '"$S" not found. You need to call "Get.put($S())" or "Get.lazyPut(()=>$S())"';
}
}
/// Replace a parent instance of a class in dependency management
/// with a [child] instance
/// - [tag] optional, if you use a [tag] to register the Instance.
void replace<P>(P child, {String? tag}) {
final info = GetInstance().getInstanceInfo<P>(tag: tag);
final info = getInstanceInfo<P>(tag: tag);
final permanent = (info.isPermanent ?? false);
delete<P>(tag: tag, force: permanent);
put(child, tag: tag, permanent: permanent);
... ... @@ -152,9 +309,251 @@ extension Inst on GetInterface {
/// the parent instance was permanent
void lazyReplace<P>(InstanceBuilderCallback<P> builder,
{String? tag, bool? fenix}) {
final info = GetInstance().getInstanceInfo<P>(tag: tag);
final info = getInstanceInfo<P>(tag: tag);
final permanent = (info.isPermanent ?? false);
delete<P>(tag: tag, force: permanent);
lazyPut(builder, tag: tag, fenix: fenix ?? permanent);
}
/// Generates the key based on [type] (and optionally a [name])
/// to register an Instance Builder in the hashmap.
String _getKey(Type type, String? name) {
return name == null ? type.toString() : type.toString() + name;
}
/// Clears all registered instances (and/or tags).
/// Even the persistent ones.
/// This should be used at the end or tearDown of unit tests.
///
/// `clearFactory` clears the callbacks registered by [lazyPut]
/// `clearRouteBindings` clears Instances associated with routes.
///
bool resetInstance({bool clearRouteBindings = true}) {
// if (clearFactory) _factory.clear();
// deleteAll(force: true);
if (clearRouteBindings) RouterReportManager.instance.clearRouteKeys();
_singl.clear();
return true;
}
/// Delete registered Class Instance [S] (or [tag]) and, closes any open
/// controllers `DisposableInterface`, cleans up the memory
///
/// /// Deletes the Instance<[S]>, cleaning the memory.
// ///
// /// - [tag] Optional "tag" used to register the Instance
// /// - [key] For internal usage, is the processed key used to register
// /// the Instance. **don't use** it unless you know what you are doing.
/// Deletes the Instance<[S]>, cleaning the memory and closes any open
/// controllers (`DisposableInterface`).
///
/// - [tag] Optional "tag" used to register the Instance
/// - [key] For internal usage, is the processed key used to register
/// the Instance. **don't use** it unless you know what you are doing.
/// - [force] Will delete an Instance even if marked as `permanent`.
bool delete<S>({String? tag, String? key, bool force = false}) {
final newKey = key ?? _getKey(S, tag);
if (!_singl.containsKey(newKey)) {
Get.log('Instance "$newKey" already removed.', isError: true);
return false;
}
final dep = _singl[newKey];
if (dep == null) return false;
final _InstanceBuilderFactory builder;
if (dep.isDirty) {
builder = dep.lateRemove ?? dep;
} else {
builder = dep;
}
if (builder.permanent && !force) {
Get.log(
// ignore: lines_longer_than_80_chars
'"$newKey" has been marked as permanent, SmartManagement is not authorized to delete it.',
isError: true,
);
return false;
}
final i = builder.dependency;
if (i is GetxServiceMixin && !force) {
return false;
}
if (i is GetLifeCycleMixin) {
i.onDelete();
Get.log('"$newKey" onDelete() called');
}
if (builder.fenix) {
builder.dependency = null;
builder.isInit = false;
return true;
} else {
if (dep.lateRemove != null) {
dep.lateRemove = null;
Get.log('"$newKey" deleted from memory');
return false;
} else {
_singl.remove(newKey);
if (_singl.containsKey(newKey)) {
Get.log('Error removing object "$newKey"', isError: true);
} else {
Get.log('"$newKey" deleted from memory');
}
return true;
}
}
}
/// Delete all registered Class Instances and, closes any open
/// controllers `DisposableInterface`, cleans up the memory
///
/// - [force] Will delete the Instances even if marked as `permanent`.
void deleteAll({bool force = false}) {
final keys = _singl.keys.toList();
for (final key in keys) {
delete(key: key, force: force);
}
}
void reloadAll({bool force = false}) {
_singl.forEach((key, value) {
if (value.permanent && !force) {
Get.log('Instance "$key" is permanent. Skipping reload');
} else {
value.dependency = null;
value.isInit = false;
Get.log('Instance "$key" was reloaded.');
}
});
}
void reload<S>({
String? tag,
String? key,
bool force = false,
}) {
final newKey = key ?? _getKey(S, tag);
final builder = _getDependency<S>(tag: tag, key: newKey);
if (builder == null) return;
if (builder.permanent && !force) {
Get.log(
'''Instance "$newKey" is permanent. Use [force = true] to force the restart.''',
isError: true,
);
return;
}
final i = builder.dependency;
if (i is GetxServiceMixin && !force) {
return;
}
if (i is GetLifeCycleMixin) {
i.onDelete();
Get.log('"$newKey" onDelete() called');
}
builder.dependency = null;
builder.isInit = false;
Get.log('Instance "$newKey" was restarted.');
}
/// Check if a Class Instance<[S]> (or [tag]) is registered in memory.
/// - [tag] is optional, if you used a [tag] to register the Instance.
bool isRegistered<S>({String? tag}) => _singl.containsKey(_getKey(S, tag));
/// Checks if a lazy factory callback `Get.lazyPut()` that returns an
/// Instance<[S]> is registered in memory.
/// - [tag] is optional, if you used a [tag] to register the lazy Instance.
bool isPrepared<S>({String? tag}) {
final newKey = _getKey(S, tag);
final builder = _getDependency<S>(tag: tag, key: newKey);
if (builder == null) {
return false;
}
if (!builder.isInit) {
return true;
}
return false;
}
}
typedef InstanceBuilderCallback<S> = S Function();
// typedef InjectorBuilderCallback<S> = S Function(Inst);
typedef AsyncInstanceBuilderCallback<S> = Future<S> Function();
/// Internal class to register instances with `Get.put<S>()`.
class _InstanceBuilderFactory<S> {
/// Marks the Builder as a single instance.
/// For reusing [dependency] instead of [builderFunc]
bool? isSingleton;
/// When fenix mode is avaliable, when a new instance is need
/// Instance manager will recreate a new instance of S
bool fenix;
/// Stores the actual object instance when [isSingleton]=true.
S? dependency;
/// Generates (and regenerates) the instance when [isSingleton]=false.
/// Usually used by factory methods
InstanceBuilderCallback<S> builderFunc;
/// Flag to persist the instance in memory,
/// without considering `Get.smartManagement`
bool permanent = false;
bool isInit = false;
_InstanceBuilderFactory<S>? lateRemove;
bool isDirty = false;
String? tag;
_InstanceBuilderFactory({
required this.isSingleton,
required this.builderFunc,
required this.permanent,
required this.isInit,
required this.fenix,
required this.tag,
required this.lateRemove,
});
void _showInitLog() {
if (tag == null) {
Get.log('Instance "$S" has been created');
} else {
Get.log('Instance "$S" has been created with tag "$tag"');
}
}
/// Gets the actual instance by it's [builderFunc] or the persisted instance.
S getDependency() {
if (isSingleton!) {
if (dependency == null) {
_showInitLog();
dependency = builderFunc();
}
return dependency!;
} else {
return builderFunc();
}
}
}
... ...
import 'dart:async';
import '../../get_core/get_core.dart';
import '../../get_navigation/src/router_report.dart';
import 'lifecycle.dart';
class InstanceInfo {
final bool? isPermanent;
final bool? isSingleton;
bool get isCreate => !isSingleton!;
final bool isRegistered;
final bool isPrepared;
final bool? isInit;
const InstanceInfo({
required this.isPermanent,
required this.isSingleton,
required this.isRegistered,
required this.isPrepared,
required this.isInit,
});
}
class GetInstance {
factory GetInstance() => _getInstance ??= GetInstance._();
const GetInstance._();
static GetInstance? _getInstance;
T call<T>() => find<T>();
/// Holds references to every registered Instance when using
/// `Get.put()`
static final Map<String, _InstanceBuilderFactory> _singl = {};
/// Holds a reference to every registered callback when using
/// `Get.lazyPut()`
// static final Map<String, _Lazy> _factory = {};
void injector<S>(
InjectorBuilderCallback<S> fn, {
String? tag,
bool fenix = false,
// bool permanent = false,
}) {
lazyPut(
() => fn(this),
tag: tag,
fenix: fenix,
// permanent: permanent,
);
}
/// async version of `Get.put()`.
/// Awaits for the resolution of the Future from `builder()` parameter and
/// stores the Instance returned.
Future<S> putAsync<S>(
AsyncInstanceBuilderCallback<S> builder, {
String? tag,
bool permanent = false,
}) async {
return put<S>(await builder(), tag: tag, permanent: permanent);
}
/// Injects an instance `<S>` in memory to be globally accessible.
///
/// No need to define the generic type `<S>` as it's inferred from
/// the [dependency]
///
/// - [dependency] The Instance to be injected.
/// - [tag] optionally, use a [tag] as an "id" to create multiple records of
/// the same Type<[S]>
/// - [permanent] keeps the Instance in memory, not following
/// `Get.smartManagement` rules.
S put<S>(
S dependency, {
String? tag,
bool permanent = false,
@deprecated InstanceBuilderCallback<S>? builder,
}) {
_insert(
isSingleton: true,
name: tag,
permanent: permanent,
builder: builder ?? (() => dependency));
return find<S>(tag: tag);
}
/// Creates a new Instance<S> lazily from the `<S>builder()` callback.
///
/// The first time you call `Get.find()`, the `builder()` callback will create
/// the Instance and persisted as a Singleton (like you would
/// use `Get.put()`).
///
/// Using `Get.smartManagement` as [SmartManagement.keepFactory] has
/// the same outcome as using `fenix:true` :
/// The internal register of `builder()` will remain in memory to recreate
/// the Instance if the Instance has been removed with `Get.delete()`.
/// Therefore, future calls to `Get.find()` will return the same Instance.
///
/// If you need to make use of GetxController's life-cycle
/// (`onInit(), onStart(), onClose()`) [fenix] is a great choice to mix with
/// `GetBuilder()` and `GetX()` widgets, and/or `GetMaterialApp` Navigation.
///
/// You could use `Get.lazyPut(fenix:true)` in your app's `main()` instead
/// of `Bindings()` for each `GetPage`.
/// And the memory management will be similar.
///
/// Subsequent calls to `Get.lazyPut()` with the same parameters
/// (<[S]> and optionally [tag] will **not** override the original).
void lazyPut<S>(
InstanceBuilderCallback<S> builder, {
String? tag,
bool? fenix,
bool permanent = false,
}) {
_insert(
isSingleton: true,
name: tag,
permanent: permanent,
builder: builder,
fenix: fenix ?? Get.smartManagement == SmartManagement.keepFactory,
);
}
/// Creates a new Class Instance [S] from the builder callback[S].
/// Every time [find]<[S]>() is used, it calls the builder method to generate
/// a new Instance [S].
/// It also registers each `instance.onClose()` with the current
/// Route `Get.reference` to keep the lifecycle active.
/// Is important to know that the instances created are only stored per Route.
/// So, if you call `Get.delete<T>()` the "instance factory" used in this
/// method (`Get.create<T>()`) will be removed, but NOT the instances
/// already created by it.
///
/// Example:
///
/// ```create(() => Repl());
/// Repl a = find();
/// Repl b = find();
/// print(a==b); (false)```
void create<S>(
InstanceBuilderCallback<S> builder, {
String? tag,
bool permanent = true,
}) {
_insert(
isSingleton: false,
name: tag,
builder: builder,
permanent: permanent,
);
}
/// Injects the Instance [S] builder into the `_singleton` HashMap.
void _insert<S>({
bool? isSingleton,
String? name,
bool permanent = false,
required InstanceBuilderCallback<S> builder,
bool fenix = false,
}) {
final key = _getKey(S, name);
_InstanceBuilderFactory<S>? dep;
if (_singl.containsKey(key)) {
final _dep = _singl[key];
if (_dep == null || !_dep.isDirty) {
return;
} else {
dep = _dep as _InstanceBuilderFactory<S>;
}
}
_singl[key] = _InstanceBuilderFactory<S>(
isSingleton: isSingleton,
builderFunc: builder,
permanent: permanent,
isInit: false,
fenix: fenix,
tag: name,
lateRemove: dep,
);
}
/// Initializes the dependencies for a Class Instance [S] (or tag),
/// If its a Controller, it starts the lifecycle process.
/// Optionally associating the current Route to the lifetime of the instance,
/// if `Get.smartManagement` is marked as [SmartManagement.full] or
/// [SmartManagement.keepFactory]
/// Only flags `isInit` if it's using `Get.create()`
/// (not for Singletons access).
/// Returns the instance if not initialized, required for Get.create() to
/// work properly.
S? _initDependencies<S>({String? name}) {
final key = _getKey(S, name);
final isInit = _singl[key]!.isInit;
S? i;
if (!isInit) {
i = _startController<S>(tag: name);
if (_singl[key]!.isSingleton!) {
_singl[key]!.isInit = true;
if (Get.smartManagement != SmartManagement.onlyBuilder) {
RouterReportManager.instance
.reportDependencyLinkedToRoute(_getKey(S, name));
}
}
}
return i;
}
InstanceInfo getInstanceInfo<S>({String? tag}) {
final build = _getDependency<S>(tag: tag);
return InstanceInfo(
isPermanent: build?.permanent,
isSingleton: build?.isSingleton,
isRegistered: isRegistered<S>(tag: tag),
isPrepared: !(build?.isInit ?? true),
isInit: build?.isInit,
);
}
_InstanceBuilderFactory? _getDependency<S>({String? tag, String? key}) {
final newKey = key ?? _getKey(S, tag);
if (!_singl.containsKey(newKey)) {
Get.log('Instance "$newKey" is not registered.', isError: true);
return null;
} else {
return _singl[newKey];
}
}
void markAsDirty<S>({String? tag, String? key}) {
final newKey = key ?? _getKey(S, tag);
if (_singl.containsKey(newKey)) {
final dep = _singl[newKey];
if (dep != null && !dep.permanent) {
dep.isDirty = true;
}
}
}
/// Initializes the controller
S _startController<S>({String? tag}) {
final key = _getKey(S, tag);
final i = _singl[key]!.getDependency() as S;
if (i is GetLifeCycleMixin) {
i.onStart();
if (tag == null) {
Get.log('Instance "$S" has been initialized');
} else {
Get.log('Instance "$S" with tag "$tag" has been initialized');
}
if (!_singl[key]!.isSingleton!) {
RouterReportManager.instance.appendRouteByCreate(i);
}
}
return i;
}
S putOrFind<S>(InstanceBuilderCallback<S> dep, {String? tag}) {
final key = _getKey(S, tag);
if (_singl.containsKey(key)) {
return _singl[key]!.getDependency() as S;
} else {
return GetInstance().put(dep(), tag: tag);
}
}
/// Finds the registered type <[S]> (or [tag])
/// In case of using Get.[create] to register a type <[S]> or [tag],
/// it will create an instance each time you call [find].
/// If the registered type <[S]> (or [tag]) is a Controller,
/// it will initialize it's lifecycle.
S find<S>({String? tag}) {
final key = _getKey(S, tag);
if (isRegistered<S>(tag: tag)) {
final dep = _singl[key];
if (dep == null) {
if (tag == null) {
throw 'Class "$S" is not registered';
} else {
throw 'Class "$S" with tag "$tag" is not registered';
}
}
// if (dep.lateRemove != null) {
// dep.isDirty = true;
// if(dep.fenix)
// }
/// although dirty solution, the lifecycle starts inside
/// `initDependencies`, so we have to return the instance from there
/// to make it compatible with `Get.create()`.
final i = _initDependencies<S>(name: tag);
return i ?? dep.getDependency() as S;
} else {
// ignore: lines_longer_than_80_chars
throw '"$S" not found. You need to call "Get.put($S())" or "Get.lazyPut(()=>$S())"';
}
}
/// Generates the key based on [type] (and optionally a [name])
/// to register an Instance Builder in the hashmap.
String _getKey(Type type, String? name) {
return name == null ? type.toString() : type.toString() + name;
}
/// Clears all registered instances (and/or tags).
/// Even the persistent ones.
/// This should be used at the end or tearDown of unit tests.
///
/// `clearFactory` clears the callbacks registered by [lazyPut]
/// `clearRouteBindings` clears Instances associated with routes.
///
bool resetInstance(
{@deprecated bool clearFactory = true, bool clearRouteBindings = true}) {
// if (clearFactory) _factory.clear();
// deleteAll(force: true);
if (clearRouteBindings) RouterReportManager.instance.clearRouteKeys();
_singl.clear();
return true;
}
/// Delete registered Class Instance [S] (or [tag]) and, closes any open
/// controllers `DisposableInterface`, cleans up the memory
///
/// /// Deletes the Instance<[S]>, cleaning the memory.
// ///
// /// - [tag] Optional "tag" used to register the Instance
// /// - [key] For internal usage, is the processed key used to register
// /// the Instance. **don't use** it unless you know what you are doing.
/// Deletes the Instance<[S]>, cleaning the memory and closes any open
/// controllers (`DisposableInterface`).
///
/// - [tag] Optional "tag" used to register the Instance
/// - [key] For internal usage, is the processed key used to register
/// the Instance. **don't use** it unless you know what you are doing.
/// - [force] Will delete an Instance even if marked as `permanent`.
bool delete<S>({String? tag, String? key, bool force = false}) {
final newKey = key ?? _getKey(S, tag);
if (!_singl.containsKey(newKey)) {
Get.log('Instance "$newKey" already removed.', isError: true);
return false;
}
final dep = _singl[newKey];
if (dep == null) return false;
final _InstanceBuilderFactory builder;
if (dep.isDirty) {
builder = dep.lateRemove ?? dep;
} else {
builder = dep;
}
if (builder.permanent && !force) {
Get.log(
// ignore: lines_longer_than_80_chars
'"$newKey" has been marked as permanent, SmartManagement is not authorized to delete it.',
isError: true,
);
return false;
}
final i = builder.dependency;
if (i is GetxServiceMixin && !force) {
return false;
}
if (i is GetLifeCycleMixin) {
i.onDelete();
Get.log('"$newKey" onDelete() called');
}
if (builder.fenix) {
builder.dependency = null;
builder.isInit = false;
return true;
} else {
if (dep.lateRemove != null) {
dep.lateRemove = null;
Get.log('"$newKey" deleted from memory');
return false;
} else {
_singl.remove(newKey);
if (_singl.containsKey(newKey)) {
Get.log('Error removing object "$newKey"', isError: true);
} else {
Get.log('"$newKey" deleted from memory');
}
return true;
}
}
}
/// Delete all registered Class Instances and, closes any open
/// controllers `DisposableInterface`, cleans up the memory
///
/// - [force] Will delete the Instances even if marked as `permanent`.
void deleteAll({bool force = false}) {
final keys = _singl.keys.toList();
for (final key in keys) {
delete(key: key, force: force);
}
}
void reloadAll({bool force = false}) {
_singl.forEach((key, value) {
if (value.permanent && !force) {
Get.log('Instance "$key" is permanent. Skipping reload');
} else {
value.dependency = null;
value.isInit = false;
Get.log('Instance "$key" was reloaded.');
}
});
}
void reload<S>({
String? tag,
String? key,
bool force = false,
}) {
final newKey = key ?? _getKey(S, tag);
final builder = _getDependency<S>(tag: tag, key: newKey);
if (builder == null) return;
if (builder.permanent && !force) {
Get.log(
'''Instance "$newKey" is permanent. Use [force = true] to force the restart.''',
isError: true,
);
return;
}
final i = builder.dependency;
if (i is GetxServiceMixin && !force) {
return;
}
if (i is GetLifeCycleMixin) {
i.onDelete();
Get.log('"$newKey" onDelete() called');
}
builder.dependency = null;
builder.isInit = false;
Get.log('Instance "$newKey" was restarted.');
}
/// Check if a Class Instance<[S]> (or [tag]) is registered in memory.
/// - [tag] is optional, if you used a [tag] to register the Instance.
bool isRegistered<S>({String? tag}) => _singl.containsKey(_getKey(S, tag));
/// Checks if a lazy factory callback `Get.lazyPut()` that returns an
/// Instance<[S]> is registered in memory.
/// - [tag] is optional, if you used a [tag] to register the lazy Instance.
bool isPrepared<S>({String? tag}) {
final newKey = _getKey(S, tag);
final builder = _getDependency<S>(tag: tag, key: newKey);
if (builder == null) {
return false;
}
if (!builder.isInit) {
return true;
}
return false;
}
}
typedef InstanceBuilderCallback<S> = S Function();
typedef InjectorBuilderCallback<S> = S Function(GetInstance);
typedef AsyncInstanceBuilderCallback<S> = Future<S> Function();
/// Internal class to register instances with `Get.put<S>()`.
class _InstanceBuilderFactory<S> {
/// Marks the Builder as a single instance.
/// For reusing [dependency] instead of [builderFunc]
bool? isSingleton;
/// When fenix mode is avaliable, when a new instance is need
/// Instance manager will recreate a new instance of S
bool fenix;
/// Stores the actual object instance when [isSingleton]=true.
S? dependency;
/// Generates (and regenerates) the instance when [isSingleton]=false.
/// Usually used by factory methods
InstanceBuilderCallback<S> builderFunc;
/// Flag to persist the instance in memory,
/// without considering `Get.smartManagement`
bool permanent = false;
bool isInit = false;
_InstanceBuilderFactory<S>? lateRemove;
bool isDirty = false;
String? tag;
_InstanceBuilderFactory({
required this.isSingleton,
required this.builderFunc,
required this.permanent,
required this.isInit,
required this.fenix,
required this.tag,
required this.lateRemove,
});
void _showInitLog() {
if (tag == null) {
Get.log('Instance "$S" has been created');
} else {
Get.log('Instance "$S" has been created with tag "$tag"');
}
}
/// Gets the actual instance by it's [builderFunc] or the persisted instance.
S getDependency() {
if (isSingleton!) {
if (dependency == null) {
_showInitLog();
dependency = builderFunc();
}
return dependency!;
} else {
return builderFunc();
}
}
}
... ... @@ -304,8 +304,8 @@ extension ExtensionSnackbar on GetInterface {
AnimationController? progressIndicatorController,
Color? progressIndicatorBackgroundColor,
Animation<Color>? progressIndicatorValueColor,
SnackPosition snackPosition = SnackPosition.BOTTOM,
SnackStyle snackStyle = SnackStyle.FLOATING,
SnackPosition snackPosition = SnackPosition.bottom,
SnackStyle snackStyle = SnackStyle.floating,
Curve forwardAnimationCurve = Curves.easeOutCirc,
Curve reverseAnimationCurve = Curves.easeOutCirc,
Duration animationDuration = const Duration(seconds: 1),
... ... @@ -432,7 +432,7 @@ extension ExtensionSnackbar on GetInterface {
fontSize: 14,
),
),
snackPosition: snackPosition ?? SnackPosition.TOP,
snackPosition: snackPosition ?? SnackPosition.top,
borderRadius: borderRadius ?? 15,
margin: margin ?? EdgeInsets.symmetric(horizontal: 10),
duration: duration,
... ... @@ -455,7 +455,7 @@ extension ExtensionSnackbar on GetInterface {
progressIndicatorController: progressIndicatorController,
progressIndicatorBackgroundColor: progressIndicatorBackgroundColor,
progressIndicatorValueColor: progressIndicatorValueColor,
snackStyle: snackStyle ?? SnackStyle.FLOATING,
snackStyle: snackStyle ?? SnackStyle.floating,
forwardAnimationCurve: forwardAnimationCurve ?? Curves.easeOutCirc,
reverseAnimationCurve: reverseAnimationCurve ?? Curves.easeOutCirc,
animationDuration: animationDuration ?? Duration(seconds: 1),
... ... @@ -498,7 +498,7 @@ extension GetNavigationExt on GetInterface {
/// If you want the same behavior of ios that pops a route when the user drag,
/// you can set [popGesture] to true
///
/// If you're using the [Bindings] api, you must define it here
/// If you're using the [BindingsInterface] api, you must define it here
///
/// By default, GetX will prevent you from push a route that you already in,
/// if you want to push anyway, set [preventDuplicates] to false
... ... @@ -518,7 +518,7 @@ extension GetNavigationExt on GetInterface {
double Function(BuildContext context)? gestureWidth,
bool rebuildStack = true,
PreventDuplicateHandlingMode preventDuplicateHandlingMode =
PreventDuplicateHandlingMode.ReorderRoutes}) {
PreventDuplicateHandlingMode.reorderRoutes}) {
return searchDelegate(id).to(
page,
opaque: opaque,
... ... @@ -876,7 +876,7 @@ extension GetNavigationExt on GetInterface {
/// If you want the same behavior of ios that pops a route when the user drag,
/// you can set [popGesture] to true
///
/// If you're using the [Bindings] api, you must define it here
/// If you're using the [BindingsInterface] api, you must define it here
///
/// By default, GetX will prevent you from push a route that you already in,
/// if you want to push anyway, set [preventDuplicates] to false
... ... @@ -956,7 +956,7 @@ extension GetNavigationExt on GetInterface {
/// If you want the same behavior of ios that pops a route when the user drag,
/// you can set [popGesture] to true
///
/// If you're using the [Bindings] api, you must define it here
/// If you're using the [BindingsInterface] api, you must define it here
///
/// By default, GetX will prevent you from push a route that you already in,
/// if you want to push anyway, set [preventDuplicates] to false
... ... @@ -1077,18 +1077,7 @@ extension GetNavigationExt on GetInterface {
}
GetDelegate? nestedKey(String? key) {
if (key == null) {
return routerDelegate as GetDelegate;
}
keys.putIfAbsent(
key,
() => GetDelegate(
showHashOnUrl: true,
//debugLabel: 'Getx nested key: ${key.toString()}',
pages: RouteDecoder.fromRoute(key).currentChildrens ?? [],
),
);
return keys[key];
return _getxController.nestedKey(key);
}
GetDelegate searchDelegate(dynamic k) {
... ... @@ -1262,88 +1251,50 @@ extension GetNavigationExt on GetInterface {
set parameters(Map<String, String?> newParameters) =>
_getxController.parameters = newParameters;
CustomTransition? get customTransition => _getxController.customTransition;
set customTransition(CustomTransition? newTransition) =>
_getxController.customTransition = newTransition;
bool get testMode => _getxController.testMode;
set testMode(bool isTest) => _getxController.testMode = isTest;
void resetRootNavigator() {
_getxController = GetMaterialController();
}
static GetMaterialController _getxController = GetMaterialController();
}
extension NavTwoExt on GetInterface {
void addPages(List<GetPage> getPages) {
routeTree.addRoutes(getPages);
}
void clearRouteTree() {
_routeTree.routes.clear();
}
static late final _routeTree = ParseRouteTree(routes: []);
ParseRouteTree get routeTree => _routeTree;
/// Casts the stored router delegate to a desired type
TDelegate? delegate<TDelegate extends RouterDelegate<TPage>, TPage>() =>
_getxController.routerDelegate as TDelegate?;
void addPage(GetPage getPage) {
routeTree.addRoute(getPage);
}
// void resetRootNavigator() {
// _getxController = GetMaterialController();
// }
void removePage(GetPage getPage) {
routeTree.removeRoute(getPage);
}
// RouterDelegate? get routerDelegate => _getxController.routerDelegate;
// RouteInformationParser? get routeInformationParser =>
// _getxController.routeInformationParser;
/// Casts the stored router delegate to a desired type
TDelegate? delegate<TDelegate extends RouterDelegate<TPage>, TPage>() =>
routerDelegate as TDelegate?;
GetMaterialController get _getxController => GetMaterialController.to;
// // ignore: use_setters_to_change_properties
// void setDefaultDelegate(RouterDelegate? delegate) {
// _routerDelegate = delegate;
// void addPages(List<GetPage> getPages) {
// routeTree.addRoutes(getPages);
// }
// GetDelegate? getDelegate() => delegate<GetDelegate, GetNavConfig>();
// void clearRouteTree() {
// routeTree.routes.clear();
// }
GetInformationParser createInformationParser({String initialRoute = '/'}) {
if (routeInformationParser == null) {
return routeInformationParser = GetInformationParser(
initialRoute: initialRoute,
);
} else {
return routeInformationParser as GetInformationParser;
}
}
// ParseRouteTree get routeTree {
// final delegate = _getxController.routerDelegate;
// if (delegate is GetDelegate) {
// return delegate.routeTree;
// } else {
// //TODO: Urgent: Refactor this
// return ParseRouteTree(routes: []);
// }
// }
// static GetDelegate? _delegate;
// void addPage(GetPage getPage) {
// routeTree.addRoute(getPage);
// }
GetDelegate createDelegate({
GetPage<dynamic>? notFoundRoute,
List<GetPage> pages = const [],
List<NavigatorObserver>? navigatorObservers,
TransitionDelegate<dynamic>? transitionDelegate,
PopMode backButtonPopMode = PopMode.History,
PreventDuplicateHandlingMode preventDuplicateHandlingMode =
PreventDuplicateHandlingMode.ReorderRoutes,
GlobalKey<NavigatorState>? navigatorKey,
}) {
if (routerDelegate == null) {
return routerDelegate = GetDelegate(
notFoundRoute: notFoundRoute,
navigatorObservers: navigatorObservers,
transitionDelegate: transitionDelegate,
backButtonPopMode: backButtonPopMode,
preventDuplicateHandlingMode: preventDuplicateHandlingMode,
pages: pages,
navigatorKey: navigatorKey,
);
} else {
return routerDelegate as GetDelegate;
}
}
// void removePage(GetPage getPage) {
// routeTree.removeRoute(getPage);
// }
}
extension OverlayExt on GetInterface {
... ...
... ... @@ -192,11 +192,11 @@ class GetCupertinoApp extends StatelessWidget {
init: Get.rootController,
dispose: (d) {
onDispose?.call();
Get.clearRouteTree();
Get.clearTranslations();
Get.resetRootNavigator();
Get.routerDelegate = null;
Get.routeInformationParser = null;
// Get.clearRouteTree();
// Get.clearTranslations();
// Get.resetRootNavigator();
// Get.routerDelegate = null;
// Get.routeInformationParser = null;
},
initState: (i) {
Get.engine.addPostFrameCallback((timeStamp) {
... ... @@ -212,19 +212,19 @@ class GetCupertinoApp extends StatelessWidget {
Get.addTranslations(translationsKeys!);
}
Get.customTransition = customTransition;
// Get.customTransition = customTransition;
initialBinding?.dependencies();
if (getPages != null) {
Get.addPages(getPages!);
} else {
Get.addPage(
GetPage(
name: _cleanRouteName("/${home.runtimeType}"),
page: () => home!,
),
);
}
// if (getPages != null) {
// Get.addPages(getPages!);
// } else {
// Get.addPage(
// GetPage(
// name: _cleanRouteName("/${home.runtimeType}"),
// page: () => home!,
// ),
// );
// }
Get.smartManagement = smartManagement;
onInit?.call();
... ... @@ -240,7 +240,7 @@ class GetCupertinoApp extends StatelessWidget {
);
},
builder: (_) {
final routerDelegate = Get.createDelegate(
final routerDelegate = _.createDelegate(
pages: getPages ?? [],
notFoundRoute: unknownRoute,
navigatorKey: navigatorKey,
... ... @@ -252,7 +252,7 @@ class GetCupertinoApp extends StatelessWidget {
GetObserver(routingCallback, Get.routing)
]
..addAll(navigatorObservers!)));
final routeInformationParser = Get.createInformationParser(
final routeInformationParser = _.createInformationParser(
initialRoute: initialRoute ??
getPages?.first.name ??
_cleanRouteName("/${home.runtimeType}"),
... ... @@ -297,16 +297,16 @@ class GetCupertinoApp extends StatelessWidget {
);
}
Route<dynamic> generator(RouteSettings settings) {
return PageRedirect(settings: settings, unknownRoute: unknownRoute).page();
}
// Route<dynamic> generator(RouteSettings settings) {
// return PageRedirect(settings: settings, unknownRoute: unknownRoute).page();
// }
List<Route<dynamic>> initialRoutesGenerate(String name) {
return [
PageRedirect(
settings: RouteSettings(name: name),
unknownRoute: unknownRoute,
).page()
];
}
// List<Route<dynamic>> initialRoutesGenerate(String name) {
// return [
// PageRedirect(
// settings: RouteSettings(name: name),
// unknownRoute: unknownRoute,
// ).page()
// ];
// }
}
... ...
... ... @@ -6,10 +6,10 @@ import '../../../get_instance/get_instance.dart';
import '../../../get_state_manager/get_state_manager.dart';
import '../../../get_utils/get_utils.dart';
import '../../get_navigation.dart';
import '../router_report.dart';
class GetMaterialApp extends StatelessWidget {
final GlobalKey<NavigatorState>? navigatorKey;
final GlobalKey<ScaffoldMessengerState>? scaffoldMessengerKey;
final Widget? home;
final Map<String, WidgetBuilder>? routes;
... ... @@ -56,7 +56,7 @@ class GetMaterialApp extends StatelessWidget {
final LogWriterCallback? logWriterCallback;
final bool? popGesture;
final SmartManagement smartManagement;
final BindingsInterface? initialBinding;
final List<Bind> binds;
final Duration? transitionDuration;
final bool? defaultGlobalState;
final List<GetPage>? getPages;
... ... @@ -66,7 +66,8 @@ class GetMaterialApp extends StatelessWidget {
final RouterDelegate<Object>? routerDelegate;
final BackButtonDispatcher? backButtonDispatcher;
final bool useInheritedMediaQuery;
GetMaterialApp({
const GetMaterialApp({
Key? key,
this.navigatorKey,
this.scaffoldMessengerKey,
... ... @@ -118,7 +119,7 @@ class GetMaterialApp extends StatelessWidget {
this.transitionDuration,
this.defaultGlobalState,
this.smartManagement = SmartManagement.full,
this.initialBinding,
this.binds = const [],
this.unknownRoute,
this.highContrastTheme,
this.highContrastDarkTheme,
... ... @@ -129,17 +130,6 @@ class GetMaterialApp extends StatelessWidget {
routerDelegate = null,
super(key: key);
static String _cleanRouteName(String name) {
name = name.replaceAll('() => ', '');
/// uncommonent for URL styling.
// name = name.paramCase!;
if (!name.startsWith('/')) {
name = '/$name';
}
return Uri.tryParse(name)?.toString() ?? name;
}
GetMaterialApp.router({
Key? key,
this.routeInformationProvider,
... ... @@ -186,7 +176,7 @@ class GetMaterialApp extends StatelessWidget {
this.logWriterCallback,
this.popGesture,
this.smartManagement = SmartManagement.full,
this.initialBinding,
this.binds = const [],
this.transitionDuration,
this.defaultGlobalState,
this.getPages,
... ... @@ -202,92 +192,80 @@ class GetMaterialApp extends StatelessWidget {
super(key: key);
@override
Widget build(BuildContext context) => GetBuilder<GetMaterialController>(
init: Get.rootController,
dispose: (d) {
onDispose?.call();
Get.clearRouteTree();
Widget build(BuildContext context) {
return Binds(
binds: [
Bind.lazyPut<GetMaterialController>(
() => GetMaterialController(
ConfigData(
backButtonDispatcher: backButtonDispatcher,
binds: binds,
customTransition: customTransition,
defaultGlobalState: defaultGlobalState,
defaultTransition: defaultTransition,
enableLog: enableLog,
fallbackLocale: fallbackLocale,
getPages: getPages,
home: home,
initialRoute: initialRoute,
locale: locale,
logWriterCallback: logWriterCallback,
navigatorKey: navigatorKey,
navigatorObservers: navigatorObservers,
onDispose: onDispose,
onInit: onInit,
onReady: onReady,
opaqueRoute: opaqueRoute,
popGesture: popGesture,
routeInformationParser: routeInformationParser,
routeInformationProvider: routeInformationProvider,
routerDelegate: routerDelegate,
routingCallback: routingCallback,
scaffoldMessengerKey: scaffoldMessengerKey,
smartManagement: smartManagement,
transitionDuration: transitionDuration,
translations: translations,
translationsKeys: translationsKeys,
unknownRoute: unknownRoute,
),
),
onClose: () {
Get.clearTranslations();
Get.resetRootNavigator();
Get.routerDelegate = null;
Get.routeInformationParser = null;
RouterReportManager.dispose();
Get.resetInstance(clearRouteBindings: true);
},
initState: (i) {
// Get.routerDelegate = routerDelegate;
// Get.routeInformationParser = routeInformationParser;
Get.engine.addPostFrameCallback((timeStamp) {
onReady?.call();
});
if (locale != null) Get.locale = locale;
if (fallbackLocale != null) Get.fallbackLocale = fallbackLocale;
if (translations != null) {
Get.addTranslations(translations!.keys);
} else if (translationsKeys != null) {
Get.addTranslations(translationsKeys!);
}
Get.customTransition = customTransition;
initialBinding?.dependencies();
if (getPages != null) {
Get.addPages(getPages!);
} else {
Get.addPage(
GetPage(
name: _cleanRouteName("/${home.runtimeType}"),
page: () => home!,
),
);
}
//Get.setDefaultDelegate(routerDelegate);
Get.smartManagement = smartManagement;
onInit?.call();
Get.config(
enableLog: enableLog ?? Get.isLogEnable,
logWriterCallback: logWriterCallback,
defaultTransition: defaultTransition ?? Get.defaultTransition,
defaultOpaqueRoute: opaqueRoute ?? Get.isOpaqueRouteDefault,
defaultPopGesture: popGesture ?? Get.isPopGestureEnable,
defaultDurationTransition:
transitionDuration ?? Get.defaultTransitionDuration,
);
},
builder: (_) {
final routerDelegate = Get.createDelegate(
pages: getPages ?? [],
notFoundRoute: unknownRoute,
navigatorKey: navigatorKey,
navigatorObservers: (navigatorObservers == null
? <NavigatorObserver>[GetObserver(routingCallback, Get.routing)]
: <NavigatorObserver>[
GetObserver(routingCallback, Get.routing),
...navigatorObservers!
]));
final routeInformationParser = Get.createInformationParser(
initialRoute: initialRoute ??
getPages?.first.name ??
_cleanRouteName("/${home.runtimeType}"),
);
...binds,
],
child: Builder(builder: (context) {
final controller = context.listen<GetMaterialController>();
return MaterialApp.router(
routerDelegate: routerDelegate,
routeInformationParser: routeInformationParser,
routerDelegate: controller.routerDelegate,
routeInformationParser: controller.routeInformationParser,
backButtonDispatcher: backButtonDispatcher,
routeInformationProvider: routeInformationProvider,
key: _.unikey,
builder: defaultBuilder,
key: controller.unikey,
builder: (context, child) => Directionality(
textDirection: textDirection ??
(rtlLanguages.contains(Get.locale?.languageCode)
? TextDirection.rtl
: TextDirection.ltr),
child: builder == null
? (child ?? Material())
: builder!(context, child ?? Material()),
),
title: title,
onGenerateTitle: onGenerateTitle,
color: color,
theme: _.theme ?? theme ?? ThemeData.fallback(),
darkTheme: _.darkTheme ?? darkTheme ?? theme ?? ThemeData.fallback(),
themeMode: _.themeMode ?? themeMode,
theme: controller.theme ?? theme ?? ThemeData.fallback(),
darkTheme: controller.darkTheme ??
darkTheme ??
theme ??
ThemeData.fallback(),
themeMode: controller.themeMode ?? themeMode,
locale: Get.locale ?? locale,
scaffoldMessengerKey: scaffoldMessengerKey ?? _.scaffoldMessengerKey,
scaffoldMessengerKey:
scaffoldMessengerKey ?? controller.scaffoldMessengerKey,
localizationsDelegates: localizationsDelegates,
localeListResolutionCallback: localeListResolutionCallback,
localeResolutionCallback: localeResolutionCallback,
... ... @@ -302,30 +280,7 @@ class GetMaterialApp extends StatelessWidget {
scrollBehavior: scrollBehavior,
useInheritedMediaQuery: useInheritedMediaQuery,
);
});
Widget defaultBuilder(BuildContext context, Widget? child) {
return Directionality(
textDirection: textDirection ??
(rtlLanguages.contains(Get.locale?.languageCode)
? TextDirection.rtl
: TextDirection.ltr),
child: builder == null
? (child ?? Material())
: builder!(context, child ?? Material()),
}),
);
}
Route<dynamic> generator(RouteSettings settings) {
return PageRedirect(settings: settings, unknownRoute: unknownRoute).page();
}
// List<Route<dynamic>> initialRoutesGenerate(String name) {
// return [
// PageRedirect(
// settings: RouteSettings(name: name),
// unknownRoute: unknownRoute,
// ).page()
// ];
// }
}
... ...
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import '../../../get.dart';
class ConfigData {
final ValueChanged<Routing?>? routingCallback;
final Transition? defaultTransition;
final bool? opaqueRoute;
final VoidCallback? onInit;
final VoidCallback? onReady;
final VoidCallback? onDispose;
final bool? enableLog;
final LogWriterCallback? logWriterCallback;
final bool? popGesture;
final SmartManagement smartManagement;
final List<Bind> binds;
final Duration? transitionDuration;
final bool? defaultGlobalState;
final List<GetPage>? getPages;
final GetPage? unknownRoute;
final RouteInformationProvider? routeInformationProvider;
final RouteInformationParser<Object>? routeInformationParser;
final RouterDelegate<Object>? routerDelegate;
final BackButtonDispatcher? backButtonDispatcher;
final List<NavigatorObserver>? navigatorObservers;
final GlobalKey<NavigatorState>? navigatorKey;
final GlobalKey<ScaffoldMessengerState>? scaffoldMessengerKey;
final Map<String, Map<String, String>>? translationsKeys;
final Translations? translations;
final Locale? locale;
final Locale? fallbackLocale;
final String? initialRoute;
final CustomTransition? customTransition;
final Widget? home;
ConfigData({
required this.routingCallback,
required this.defaultTransition,
required this.opaqueRoute,
required this.onInit,
required this.onReady,
required this.onDispose,
required this.enableLog,
required this.logWriterCallback,
required this.popGesture,
required this.smartManagement,
required this.binds,
required this.transitionDuration,
required this.defaultGlobalState,
required this.getPages,
required this.unknownRoute,
required this.routeInformationProvider,
required this.routeInformationParser,
required this.routerDelegate,
required this.backButtonDispatcher,
required this.navigatorObservers,
required this.navigatorKey,
required this.scaffoldMessengerKey,
required this.translationsKeys,
required this.translations,
required this.locale,
required this.fallbackLocale,
required this.initialRoute,
required this.customTransition,
required this.home,
});
}
class GetMaterialController extends FullLifeCycleController {
static GetMaterialController get to => Get.find();
GetMaterialController(this.config);
static GetMaterialController get to {
return Get.find();
}
late final RouterDelegate<Object> routerDelegate;
late final RouteInformationParser<Object> routeInformationParser;
final ConfigData config;
@override
void onReady() {
config.onReady?.call();
super.onReady();
}
@override
void onInit() {
super.onInit();
if (config.getPages == null && config.home == null) {
throw 'You need add pages or home';
}
routerDelegate = config.routerDelegate ??
createDelegate(
pages: config.getPages ??
[
GetPage(
name: cleanRouteName("/${config.home.runtimeType}"),
page: () => config.home!,
),
],
notFoundRoute: config.unknownRoute,
navigatorKey: config.navigatorKey,
navigatorObservers: (config.navigatorObservers == null
? <NavigatorObserver>[
GetObserver(config.routingCallback, Get.routing)
]
: <NavigatorObserver>[
GetObserver(config.routingCallback, routing),
...config.navigatorObservers!
]),
);
routeInformationParser = config.routeInformationParser ??
createInformationParser(
initialRoute: config.initialRoute ??
config.getPages?.first.name ??
cleanRouteName("/${config.home.runtimeType}"),
);
if (config.locale != null) Get.locale = config.locale;
if (config.fallbackLocale != null) {
Get.fallbackLocale = config.fallbackLocale;
}
if (config.translations != null) {
Get.addTranslations(config.translations!.keys);
} else if (config.translationsKeys != null) {
Get.addTranslations(config.translationsKeys!);
}
customTransition = config.customTransition;
//Get.setDefaultDelegate(routerDelegate);
Get.smartManagement = config.smartManagement;
config.onInit?.call();
Get.isLogEnable = config.enableLog ?? kDebugMode;
Get.log = config.logWriterCallback ?? defaultLogWriterCallback;
defaultTransition = config.defaultTransition;
defaultOpaqueRoute = config.opaqueRoute ?? true;
defaultPopGesture = config.popGesture ?? GetPlatform.isIOS;
defaultTransitionDuration =
config.transitionDuration ?? Duration(milliseconds: 300);
// defaultTransitionCurve = Curves.easeOutQuad;
// defaultDialogTransitionCurve = Curves.easeOutQuad;
// defaultDialogTransitionDuration = Duration(milliseconds: 300);
}
String cleanRouteName(String name) {
name = name.replaceAll('() => ', '');
/// uncommonent for URL styling.
// name = name.paramCase!;
if (!name.startsWith('/')) {
name = '/$name';
}
return Uri.tryParse(name)?.toString() ?? name;
}
bool testMode = false;
Key? unikey;
... ... @@ -15,26 +172,22 @@ class GetMaterialController extends FullLifeCycleController {
bool defaultPopGesture = GetPlatform.isIOS;
bool defaultOpaqueRoute = true;
Transition? defaultTransition;
Duration defaultTransitionDuration = Duration(milliseconds: 300);
Curve defaultTransitionCurve = Curves.easeOutQuad;
Curve defaultDialogTransitionCurve = Curves.easeOutQuad;
Duration defaultDialogTransitionDuration = Duration(milliseconds: 300);
final routing = Routing();
Map<String, String?> parameters = {};
CustomTransition? customTransition;
Map<dynamic, GetDelegate> keys = {};
GlobalKey<NavigatorState> get key => rootDelegate.navigatorKey;
GetDelegate get rootDelegate => Get.createDelegate();
GetDelegate get rootDelegate => routerDelegate as GetDelegate;
GlobalKey<NavigatorState>? addKey(GlobalKey<NavigatorState> newKey) {
rootDelegate.navigatorKey = newKey;
... ... @@ -73,4 +226,48 @@ class GetMaterialController extends FullLifeCycleController {
themeMode = value;
update();
}
GetDelegate? nestedKey(String? key) {
if (key == null) {
return routerDelegate as GetDelegate;
}
keys.putIfAbsent(
key,
() => GetDelegate(
showHashOnUrl: true,
//debugLabel: 'Getx nested key: ${key.toString()}',
pages: RouteDecoder.fromRoute(key).currentChildrens ?? [],
),
);
return keys[key];
}
GetInformationParser createInformationParser({String initialRoute = '/'}) {
return GetInformationParser(
initialRoute: initialRoute,
);
}
// static GetDelegate? _delegate;
GetDelegate createDelegate({
GetPage<dynamic>? notFoundRoute,
List<GetPage> pages = const [],
List<NavigatorObserver>? navigatorObservers,
TransitionDelegate<dynamic>? transitionDelegate,
PopMode backButtonPopMode = PopMode.history,
PreventDuplicateHandlingMode preventDuplicateHandlingMode =
PreventDuplicateHandlingMode.reorderRoutes,
GlobalKey<NavigatorState>? navigatorKey,
}) {
return GetDelegate(
notFoundRoute: notFoundRoute,
navigatorObservers: navigatorObservers,
transitionDelegate: transitionDelegate,
backButtonPopMode: backButtonPopMode,
preventDuplicateHandlingMode: preventDuplicateHandlingMode,
pages: pages,
navigatorKey: navigatorKey,
);
}
}
... ...
... ... @@ -15,7 +15,16 @@ class RouterReportManager<T> {
/// non-singleton instances.
final Map<T?, HashSet<Function>> _routesByCreate = {};
static late final RouterReportManager instance = RouterReportManager();
static RouterReportManager? _instance;
RouterReportManager._();
static RouterReportManager get instance =>
_instance ??= RouterReportManager._();
static void dispose() {
_instance = null;
}
void printInstanceStack() {
Get.log(_routesKey.toString());
... ... @@ -75,7 +84,7 @@ class RouterReportManager<T> {
}
for (final element in keysToRemove) {
GetInstance().markAsDirty(key: element);
Get.markAsDirty(key: element);
//_routesKey.remove(element);
}
... ... @@ -104,7 +113,7 @@ class RouterReportManager<T> {
}
for (final element in keysToRemove) {
final value = GetInstance().delete(key: element);
final value = Get.delete(key: element);
if (value) {
_routesKey[routeName]?.remove(element);
}
... ...
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import '../../../get.dart';
import '../router_report.dart';
... ... @@ -41,6 +41,7 @@ class GetPageRoute<T> extends PageRoute<T>
GetPageRoute({
RouteSettings? settings,
this.transitionDuration = const Duration(milliseconds: 300),
this.reverseTransitionDuration = const Duration(milliseconds: 300),
this.opaque = true,
this.parameter,
this.gestureWidth,
... ... @@ -51,7 +52,8 @@ class GetPageRoute<T> extends PageRoute<T>
this.customTransition,
this.barrierDismissible = false,
this.barrierColor,
this.bindings = const [],
BindingsInterface? binding,
List<BindingsInterface> bindings = const [],
this.binds,
this.routeName,
this.page,
... ... @@ -61,14 +63,17 @@ class GetPageRoute<T> extends PageRoute<T>
this.maintainState = true,
bool fullscreenDialog = false,
this.middlewares,
}) : super(
}) : bindings = (binding == null) ? bindings : [...bindings, binding],
super(
settings: settings,
fullscreenDialog: fullscreenDialog,
// builder: (context) => Container(),
);
@override
final Duration transitionDuration;
@override
final Duration reverseTransitionDuration;
final GetPageBuilder? page;
final String? routeName;
//final String reference;
... ...
... ... @@ -19,7 +19,8 @@ class GetInformationParser extends RouteInformationParser<RouteDecoder> {
if (location == '/') {
//check if there is a corresponding page
//if not, relocate to initialRoute
if (!Get.routeTree.routes.any((element) => element.name == '/')) {
if (!(Get.rootController.routerDelegate as GetDelegate).registeredRoutes
.any((element) => element.name == '/')) {
location = initialRoute;
}
}
... ... @@ -32,9 +33,9 @@ class GetInformationParser extends RouteInformationParser<RouteDecoder> {
}
@override
RouteInformation restoreRouteInformation(RouteDecoder config) {
RouteInformation restoreRouteInformation(RouteDecoder configuration) {
return RouteInformation(
location: config.pageSettings?.name,
location: configuration.pageSettings?.name,
state: null,
);
}
... ...
... ... @@ -25,26 +25,26 @@ import '../routes/transitions_type.dart';
/// another pop will change the _activePages stack to:
/// 1) /home
enum PopMode {
History,
Page,
history,
page,
}
/// Enables the user to customize the behavior when pushing multiple routes that
/// shouldn't be duplicates
enum PreventDuplicateHandlingMode {
/// Removes the _activePages entries until it reaches the old route
PopUntilOriginalRoute,
popUntilOriginalRoute,
/// Simply don't push the new route
DoNothing,
doNothing,
/// Recommended - Moves the old route entry to the front
///
/// With this mode, you guarantee there will be only one
/// route entry for each location
ReorderRoutes,
reorderRoutes,
Recreate,
recreate,
}
mixin IGetNavigation {
... ... @@ -67,7 +67,7 @@ mixin IGetNavigation {
Future<void> popModeUntil(
String fullRoute, {
PopMode popMode = PopMode.History,
PopMode popMode = PopMode.history,
});
Future<T?> off<T>(
... ... @@ -147,6 +147,8 @@ mixin IGetNavigation {
Object? arguments,
]);
void removeRoute<T>(String name);
void back<T>([T? result]);
Future<R?> backAndtoNamed<T, R>(String page, {T? result, Object? arguments});
... ...
... ... @@ -34,6 +34,7 @@ class GetNavigator extends Navigator {
settings: settings,
);
}
return null;
},
reportsRouteUpdateToEngine: reportsRouteUpdateToEngine,
restorationScopeId: restorationScopeId,
... ...
// ignore_for_file: overridden_fields
import 'dart:async';
import 'package:flutter/cupertino.dart';
... ... @@ -20,11 +22,12 @@ class GetPage<T> extends Page<T> {
final bool maintainState;
final bool opaque;
final double Function(BuildContext context)? gestureWidth;
//final BindingsInterface? binding;
final BindingsInterface? binding;
final List<BindingsInterface> bindings;
final List<Bind> binds;
final CustomTransition? customTransition;
final Duration? transitionDuration;
final Duration? reverseTransitionDuration;
final bool fullscreenDialog;
final bool preventDuplicates;
final Completer<T?>? completer;
... ... @@ -61,7 +64,9 @@ class GetPage<T> extends Page<T> {
this.parameters,
this.opaque = true,
this.transitionDuration,
this.reverseTransitionDuration,
this.popGesture,
this.binding,
this.bindings = const [],
this.binds = const [],
this.transition,
... ... @@ -74,7 +79,7 @@ class GetPage<T> extends Page<T> {
this.showCupertinoParallax = true,
this.preventDuplicates = true,
this.preventDuplicateHandlingMode =
PreventDuplicateHandlingMode.ReorderRoutes,
PreventDuplicateHandlingMode.reorderRoutes,
this.completer,
LocalKey? key,
}) : path = _nameToRegex(name),
... ... @@ -100,10 +105,11 @@ class GetPage<T> extends Page<T> {
bool? maintainState,
bool? opaque,
List<BindingsInterface>? bindings,
// BindingsInterface? binding,
BindingsInterface? binding,
List<Bind>? binds,
CustomTransition? customTransition,
Duration? transitionDuration,
Duration? reverseTransitionDuration,
bool? fullscreenDialog,
RouteSettings? settings,
List<GetPage<T>>? children,
... ... @@ -133,8 +139,11 @@ class GetPage<T> extends Page<T> {
opaque: opaque ?? this.opaque,
bindings: bindings ?? this.bindings,
binds: binds ?? this.binds,
binding: binding ?? this.binding,
customTransition: customTransition ?? this.customTransition,
transitionDuration: transitionDuration ?? this.transitionDuration,
reverseTransitionDuration:
reverseTransitionDuration ?? this.reverseTransitionDuration,
fullscreenDialog: fullscreenDialog ?? this.fullscreenDialog,
children: children ?? this.children,
unknownRoute: unknownRoute ?? this.unknownRoute,
... ... @@ -154,7 +163,7 @@ class GetPage<T> extends Page<T> {
route: this,
settings: this,
unknownRoute: unknownRoute,
).getPageToRoute<T>(this, unknownRoute);
).getPageToRoute<T>(this, unknownRoute, context);
return _page;
}
... ... @@ -165,7 +174,7 @@ class GetPage<T> extends Page<T> {
String _replace(Match pattern) {
var buffer = StringBuffer('(?:');
if (pattern[1] != null) buffer.write('\.');
if (pattern[1] != null) buffer.write('.');
buffer.write('([\\w%+-._~!\$&\'()*,;=:@]+))');
if (pattern[3] != null) buffer.write('?');
... ...
... ... @@ -4,13 +4,12 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import '../../../get_instance/src/bindings_interface.dart';
import '../../../get_state_manager/src/simple/list_notifier.dart';
import '../../../get_utils/src/platform/platform.dart';
import '../../../route_manager.dart';
class GetDelegate extends RouterDelegate<RouteDecoder>
with
ListNotifierSingleMixin,
ChangeNotifier,
PopNavigatorRouterDelegateMixin<RouteDecoder>,
IGetNavigation {
final List<RouteDecoder> _activePages = <RouteDecoder>[];
... ... @@ -27,6 +26,30 @@ class GetDelegate extends RouterDelegate<RouteDecoder>
List<RouteDecoder> get activePages => _activePages;
final _routeTree = ParseRouteTree(routes: []);
List<GetPage> get registeredRoutes => _routeTree.routes;
void addPages(List<GetPage> getPages) {
_routeTree.addRoutes(getPages);
}
void clearRouteTree() {
_routeTree.routes.clear();
}
void addPage(GetPage getPage) {
_routeTree.addRoute(getPage);
}
void removePage(GetPage getPage) {
_routeTree.removeRoute(getPage);
}
RouteDecoder matchRoute(String name, {PageSettings? arguments}) {
return _routeTree.matchRoute(name, arguments: arguments);
}
// GlobalKey<NavigatorState> get navigatorKey => Get.key;
@override
... ... @@ -38,9 +61,9 @@ class GetDelegate extends RouterDelegate<RouteDecoder>
GetPage? notFoundRoute,
this.navigatorObservers,
this.transitionDelegate,
this.backButtonPopMode = PopMode.History,
this.backButtonPopMode = PopMode.history,
this.preventDuplicateHandlingMode =
PreventDuplicateHandlingMode.ReorderRoutes,
PreventDuplicateHandlingMode.reorderRoutes,
this.pickPagesForRootNavigator,
this.restorationScopeId,
bool showHashOnUrl = false,
... ... @@ -54,8 +77,8 @@ class GetDelegate extends RouterDelegate<RouteDecoder>
),
) {
if (!showHashOnUrl && GetPlatform.isWeb) setUrlStrategy();
Get.addPages(pages);
Get.addPage(notFoundRoute);
addPages(pages);
addPage(notFoundRoute);
Get.log('GetDelegate is created !');
}
... ... @@ -69,6 +92,16 @@ class GetDelegate extends RouterDelegate<RouteDecoder>
var redirectRes = await item.redirectDelegate(iterator);
if (redirectRes == null) return null;
iterator = redirectRes;
// Stop the iteration over the middleware if we changed page
// and that redirectRes is not the same as the current config.
if (config != redirectRes) {
break;
}
}
// If the target is not the same as the source, we need
// to run the middlewares for the new route.
if (iterator != config) {
return await runMiddleware(iterator);
}
return iterator;
}
... ... @@ -122,14 +155,14 @@ class GetDelegate extends RouterDelegate<RouteDecoder>
(element) => element.pageSettings?.name == config.pageSettings?.name);
if (originalEntryIndex >= 0) {
switch (preventDuplicateHandlingMode) {
case PreventDuplicateHandlingMode.PopUntilOriginalRoute:
popModeUntil(config.pageSettings!.name, popMode: PopMode.Page);
case PreventDuplicateHandlingMode.popUntilOriginalRoute:
popModeUntil(config.pageSettings!.name, popMode: PopMode.page);
break;
case PreventDuplicateHandlingMode.ReorderRoutes:
case PreventDuplicateHandlingMode.reorderRoutes:
await _unsafeHistoryRemoveAt(originalEntryIndex, null);
await _unsafeHistoryAdd(config);
break;
case PreventDuplicateHandlingMode.DoNothing:
case PreventDuplicateHandlingMode.doNothing:
default:
break;
}
... ... @@ -192,9 +225,9 @@ class GetDelegate extends RouterDelegate<RouteDecoder>
Future<T?> _pop<T>(PopMode mode, T result) async {
switch (mode) {
case PopMode.History:
case PopMode.history:
return await _popHistory<T>(result);
case PopMode.Page:
case PopMode.page:
return await _popPage<T>(result);
default:
return null;
... ... @@ -225,9 +258,9 @@ class GetDelegate extends RouterDelegate<RouteDecoder>
bool _canPop(mode) {
switch (mode) {
case PopMode.History:
case PopMode.history:
return _canPopHistory();
case PopMode.Page:
case PopMode.page:
default:
return _canPopPage();
}
... ... @@ -239,7 +272,7 @@ class GetDelegate extends RouterDelegate<RouteDecoder>
Iterable<GetPage> getVisualPages(RouteDecoder? currentHistory) {
final res = currentHistory!.currentTreeBranch
.where((r) => r.participatesInRootNavigator != null);
if (res.length == 0) {
if (res.isEmpty) {
//default behavoir, all routes participate in root navigator
return _activePages.map((e) => e.route!);
} else {
... ... @@ -256,7 +289,7 @@ class GetDelegate extends RouterDelegate<RouteDecoder>
? <GetPage>[]
: pickPagesForRootNavigator?.call(currentHistory).toList() ??
getVisualPages(currentHistory).toList();
if (pages.length == 0) {
if (pages.isEmpty) {
return ColoredBox(
color: Theme.of(context).scaffoldBackgroundColor,
);
... ... @@ -323,10 +356,11 @@ class GetDelegate extends RouterDelegate<RouteDecoder>
double Function(BuildContext context)? gestureWidth,
bool rebuildStack = true,
PreventDuplicateHandlingMode preventDuplicateHandlingMode =
PreventDuplicateHandlingMode.ReorderRoutes,
PreventDuplicateHandlingMode.reorderRoutes,
}) async {
routeName = _cleanRouteName("/${page.runtimeType}");
// if (preventDuplicateHandlingMode == PreventDuplicateHandlingMode.Recreate) {
// if (preventDuplicateHandlingMode ==
//PreventDuplicateHandlingMode.Recreate) {
// routeName = routeName + page.hashCode.toString();
// }
... ... @@ -345,14 +379,14 @@ class GetDelegate extends RouterDelegate<RouteDecoder>
preventDuplicateHandlingMode: preventDuplicateHandlingMode,
);
Get.addPage(getPage);
_routeTree.addRoute(getPage);
final args = _buildPageSettings(routeName, arguments);
final route = _getRouteDecoder<T>(args);
final result = await _push<T>(
route!,
rebuildStack: rebuildStack,
);
Get.removePage(getPage);
_routeTree.removeRoute(getPage);
return result;
}
... ... @@ -437,13 +471,13 @@ class GetDelegate extends RouterDelegate<RouteDecoder>
@override
Future<T?>? offAllNamed<T>(
String page, {
String newRouteName, {
// bool Function(GetPage route)? predicate,
dynamic arguments,
int? id,
Map<String, String>? parameters,
}) async {
final args = _buildPageSettings(page, arguments);
final args = _buildPageSettings(newRouteName, arguments);
final route = _getRouteDecoder<T>(args);
if (route == null) return null;
... ... @@ -530,7 +564,7 @@ class GetDelegate extends RouterDelegate<RouteDecoder>
void back<T>([T? result]) {
_checkIfCanBack();
_popWithResult<T>(result);
refresh();
notifyListeners();
}
bool get canBack {
... ... @@ -564,7 +598,7 @@ class GetDelegate extends RouterDelegate<RouteDecoder>
@override
Future<void> popModeUntil(
String fullRoute, {
PopMode popMode = PopMode.History,
PopMode popMode = PopMode.history,
}) async {
// remove history or page entries until you meet route
var iterator = currentConfiguration;
... ... @@ -575,7 +609,7 @@ class GetDelegate extends RouterDelegate<RouteDecoder>
// replace iterator
iterator = currentConfiguration;
}
refresh();
notifyListeners();
}
@override
... ... @@ -584,12 +618,12 @@ class GetDelegate extends RouterDelegate<RouteDecoder>
_popWithResult();
}
refresh();
notifyListeners();
}
Future<T?> _replace<T>(PageSettings arguments, GetPage<T> page) async {
final index = _activePages.length > 1 ? _activePages.length - 1 : 0;
Get.addPage(page);
_routeTree.addRoute(page);
final activePage = _getRouteDecoder(arguments);
... ... @@ -597,9 +631,9 @@ class GetDelegate extends RouterDelegate<RouteDecoder>
_activePages[index] = activePage!;
refresh();
notifyListeners();
final result = await activePage.route?.completer?.future as Future<T?>?;
Get.removePage(page);
_routeTree.removeRoute(page);
return result;
}
... ... @@ -609,7 +643,7 @@ class GetDelegate extends RouterDelegate<RouteDecoder>
// final activePage = _configureRouterDecoder<T>(page, arguments);
_activePages[index] = activePage;
refresh();
notifyListeners();
final result = await activePage.route?.completer?.future as Future<T?>?;
return result;
}
... ... @@ -644,7 +678,7 @@ class GetDelegate extends RouterDelegate<RouteDecoder>
page = uri.toString();
}
final decoder = Get.routeTree.matchRoute(page, arguments: arguments);
final decoder = _routeTree.matchRoute(page, arguments: arguments);
final route = decoder.route;
if (route == null) return null;
... ... @@ -680,7 +714,7 @@ class GetDelegate extends RouterDelegate<RouteDecoder>
final preventDuplicateHandlingMode =
res.route?.preventDuplicateHandlingMode ??
PreventDuplicateHandlingMode.ReorderRoutes;
PreventDuplicateHandlingMode.reorderRoutes;
final onStackPage = _activePages
.firstWhereOrNull((element) => element.route?.key == res.route?.key);
... ... @@ -691,18 +725,18 @@ class GetDelegate extends RouterDelegate<RouteDecoder>
} else {
/// There are duplicate routes, reorder
switch (preventDuplicateHandlingMode) {
case PreventDuplicateHandlingMode.DoNothing:
case PreventDuplicateHandlingMode.doNothing:
break;
case PreventDuplicateHandlingMode.ReorderRoutes:
case PreventDuplicateHandlingMode.reorderRoutes:
_activePages.remove(onStackPage);
_activePages.add(res);
break;
case PreventDuplicateHandlingMode.PopUntilOriginalRoute:
case PreventDuplicateHandlingMode.popUntilOriginalRoute:
while (_activePages.last == onStackPage) {
_popWithResult();
}
break;
case PreventDuplicateHandlingMode.Recreate:
case PreventDuplicateHandlingMode.recreate:
_activePages.remove(onStackPage);
_activePages.add(res);
break;
... ... @@ -710,7 +744,7 @@ class GetDelegate extends RouterDelegate<RouteDecoder>
}
}
if (rebuildStack) {
refresh();
notifyListeners();
}
return decoder.route?.completer?.future as Future<T?>?;
... ... @@ -757,7 +791,7 @@ class GetDelegate extends RouterDelegate<RouteDecoder>
final wasPopup = await handlePopupRoutes(result: result);
if (wasPopup) return true;
final _popped = await _pop(popMode ?? backButtonPopMode, result);
refresh();
notifyListeners();
if (_popped != null) {
//emulate the old pop with result
return true;
... ... @@ -780,7 +814,7 @@ class GetDelegate extends RouterDelegate<RouteDecoder>
_removeHistoryEntry(config, result);
}
}
refresh();
notifyListeners();
//return !route.navigator!.userGestureInProgress;
return true;
}
... ...
... ... @@ -187,8 +187,7 @@ class GetBackGestureController<T> {
// We want to cap the animation time, but we want to use a linear curve
// to determine it.
final droppedPageForwardAnimationTime = min(
lerpDouble(
_kMaxMidSwipePageForwardAnimationTime, 0, controller.value)!
lerpDouble(_kMaxMidSwipePageForwardAnimationTime, 0, controller.value)!
.floor(),
_kMaxPageBackAnimationTime,
);
... ... @@ -286,7 +285,10 @@ Cannot read the previousTitle for a route that has not yet been installed''',
@override
// A relatively rigorous eyeball estimation.
Duration get transitionDuration => const Duration(milliseconds: 400);
Duration get transitionDuration;
@override
Duration get reverseTransitionDuration;
/// Builds the primary contents of the route.
@protected
... ... @@ -360,6 +362,7 @@ Cannot read the previousTitle for a route that has not yet been installed''',
Widget child, {
bool limitedSwipe = false,
double initialOffset = 0,
Transition? transition,
}) {
// Check if the route has an animation that's currently participating
// in a back swipe gesture.
... ... @@ -408,7 +411,7 @@ Cannot read the previousTitle for a route that has not yet been installed''',
final iosAnimation = animation;
animation = CurvedAnimation(parent: animation, curve: finalCurve);
switch (route.transition ?? Get.defaultTransition) {
switch (transition ?? Get.defaultTransition) {
case Transition.leftToRight:
return SlideLeftTransition().buildTransitions(
context,
... ... @@ -714,8 +717,10 @@ Cannot read the previousTitle for a route that has not yet been installed''',
));
default:
if (Get.customTransition != null) {
return Get.customTransition!.buildTransition(context, route.curve,
final customTransition =
context.get<GetMaterialController>().customTransition;
if (customTransition != null) {
return customTransition.buildTransition(context, route.curve,
route.alignment, animation, secondaryAnimation, child);
}
... ...
... ... @@ -6,7 +6,7 @@ import '../router_report.dart';
class Dependencies {
void lazyPut<S>(InstanceBuilderCallback<S> builder,
{String? tag, bool fenix = false}) {
GetInstance().lazyPut<S>(builder, tag: tag, fenix: fenix);
Get.lazyPut<S>(builder, tag: tag, fenix: fenix);
}
S call<S>() {
... ... @@ -15,38 +15,37 @@ class Dependencies {
Future<S> putAsync<S>(AsyncInstanceBuilderCallback<S> builder,
{String? tag, bool permanent = false}) async =>
GetInstance().putAsync<S>(builder, tag: tag, permanent: permanent);
Get.putAsync<S>(builder, tag: tag, permanent: permanent);
void create<S>(InstanceBuilderCallback<S> builder,
{String? tag, bool permanent = true}) =>
GetInstance().create<S>(builder, tag: tag, permanent: permanent);
Get.create<S>(builder, tag: tag, permanent: permanent);
S find<S>({String? tag}) => GetInstance().find<S>(tag: tag);
S find<S>({String? tag}) => Get.find<S>(tag: tag);
S put<S>(S dependency,
{String? tag,
bool permanent = false,
InstanceBuilderCallback<S>? builder}) =>
GetInstance().put<S>(dependency, tag: tag, permanent: permanent);
Get.put<S>(dependency, tag: tag, permanent: permanent);
Future<bool> delete<S>({String? tag, bool force = false}) async =>
GetInstance().delete<S>(tag: tag, force: force);
Get.delete<S>(tag: tag, force: force);
Future<void> deleteAll({bool force = false}) async =>
GetInstance().deleteAll(force: force);
Get.deleteAll(force: force);
void reloadAll({bool force = false}) => GetInstance().reloadAll(force: force);
void reloadAll({bool force = false}) => Get.reloadAll(force: force);
void reload<S>({String? tag, String? key, bool force = false}) =>
GetInstance().reload<S>(tag: tag, key: key, force: force);
Get.reload<S>(tag: tag, key: key, force: force);
bool isRegistered<S>({String? tag}) =>
GetInstance().isRegistered<S>(tag: tag);
bool isRegistered<S>({String? tag}) => Get.isRegistered<S>(tag: tag);
bool isPrepared<S>({String? tag}) => GetInstance().isPrepared<S>(tag: tag);
bool isPrepared<S>({String? tag}) => Get.isPrepared<S>(tag: tag);
void replace<P>(P child, {String? tag}) {
final info = GetInstance().getInstanceInfo<P>(tag: tag);
final info = Get.getInstanceInfo<P>(tag: tag);
final permanent = (info.isPermanent ?? false);
delete<P>(tag: tag, force: permanent);
put(child, tag: tag, permanent: permanent);
... ... @@ -54,7 +53,7 @@ class Dependencies {
void lazyReplace<P>(InstanceBuilderCallback<P> builder,
{String? tag, bool? fenix}) {
final info = GetInstance().getInstanceInfo<P>(tag: tag);
final info = Get.getInstanceInfo<P>(tag: tag);
final permanent = (info.isPermanent ?? false);
delete<P>(tag: tag, force: permanent);
lazyPut(builder, tag: tag, fenix: fenix ?? permanent);
... ...
... ... @@ -208,7 +208,7 @@ class Routing {
this.isDialog,
});
void update(void fn(Routing value)) {
void update(void Function(Routing value) fn) {
fn(this);
}
}
... ...
... ... @@ -55,15 +55,12 @@ extension PageArgExt on BuildContext {
class PageSettings extends RouteSettings {
PageSettings(
this.uri, [
this.arguments,
]);
Object? arguments,
]) : super(arguments: arguments);
@override
String get name => '$uri';
@override
late final Object? arguments;
final Uri uri;
final params = <String, String>{};
... ...
... ... @@ -14,7 +14,8 @@ class RouteDecoder {
factory RouteDecoder.fromRoute(String location) {
var uri = Uri.parse(location);
final args = PageSettings(uri);
final decoder = Get.routeTree.matchRoute(location, arguments: args);
final decoder = (Get.rootController.routerDelegate as GetDelegate)
.matchRoute(location, arguments: args);
decoder.route = decoder.route?.copy(
completer: null,
arguments: args,
... ... @@ -93,7 +94,7 @@ class ParseRouteTree {
];
for (var item in split) {
if (curPath.endsWith('/')) {
curPath += '$item';
curPath += item;
} else {
curPath += '/$item';
}
... ...
import 'dart:async';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import '../../../get.dart';
... ... @@ -51,7 +52,7 @@ abstract class _RouteMiddleware {
/// }
/// ```
/// {@end-tool}
Future<RouteDecoder?> redirectDelegate(RouteDecoder route);
FutureOr<RouteDecoder?> redirectDelegate(RouteDecoder route);
/// This function will be called when this Page is called
/// you can use it to change something about the page or give it new page
... ... @@ -65,8 +66,8 @@ abstract class _RouteMiddleware {
/// {@end-tool}
GetPage? onPageCalled(GetPage page);
/// This function will be called right before the [Bindings] are initialize.
/// Here you can change [Bindings] for this page
/// This function will be called right before the [BindingsInterface] are initialize.
/// Here you can change [BindingsInterface] for this page
/// {@tool snippet}
/// ```dart
/// List<Bindings> onBindingsStart(List<Bindings> bindings) {
... ... @@ -80,7 +81,7 @@ abstract class _RouteMiddleware {
/// {@end-tool}
List<R>? onBindingsStart<R>(List<R> bindings);
/// This function will be called right after the [Bindings] are initialize.
/// This function will be called right after the [BindingsInterface] are initialize.
GetPageBuilder? onPageBuildStart(GetPageBuilder page);
/// This function will be called right after the
... ... @@ -120,8 +121,7 @@ class GetMiddleware implements _RouteMiddleware {
void onPageDispose() {}
@override
Future<RouteDecoder?> redirectDelegate(RouteDecoder route) =>
SynchronousFuture(route);
FutureOr<RouteDecoder?> redirectDelegate(RouteDecoder route) => (route);
}
class MiddlewareRunner {
... ... @@ -195,37 +195,9 @@ class PageRedirect {
});
// redirect all pages that needes redirecting
GetPageRoute<T> page<T>() {
while (needRecheck()) {}
final _r = (isUnknown ? unknownRoute : route)!;
return GetPageRoute<T>(
page: _r.page,
parameter: _r.parameters,
settings: isUnknown
? RouteSettings(
name: _r.name,
arguments: settings!.arguments,
)
: settings,
curve: _r.curve,
opaque: _r.opaque,
showCupertinoParallax: _r.showCupertinoParallax,
gestureWidth: _r.gestureWidth,
customTransition: _r.customTransition,
bindings: _r.bindings,
binds: _r.binds,
transitionDuration:
_r.transitionDuration ?? Get.defaultTransitionDuration,
transition: _r.transition,
popGesture: _r.popGesture,
fullscreenDialog: _r.fullscreenDialog,
middlewares: _r.middlewares,
);
}
// redirect all pages that needes redirecting
GetPageRoute<T> getPageToRoute<T>(GetPage rou, GetPage? unk) {
while (needRecheck()) {}
GetPageRoute<T> getPageToRoute<T>(
GetPage rou, GetPage? unk, BuildContext context) {
while (needRecheck(context)) {}
final _r = (isUnknown ? unk : rou)!;
return GetPageRoute<T>(
... ... @@ -242,9 +214,14 @@ class PageRedirect {
opaque: _r.opaque,
customTransition: _r.customTransition,
bindings: _r.bindings,
binding: _r.binding,
binds: _r.binds,
transitionDuration:
_r.transitionDuration ?? Get.defaultTransitionDuration,
reverseTransitionDuration:
_r.reverseTransitionDuration ?? Get.defaultTransitionDuration,
// performIncomeAnimation: _r.performIncomeAnimation,
// performOutGoingAnimation: _r.performOutGoingAnimation,
transition: _r.transition,
popGesture: _r.popGesture,
fullscreenDialog: _r.fullscreenDialog,
... ... @@ -253,11 +230,11 @@ class PageRedirect {
}
/// check if redirect is needed
bool needRecheck() {
bool needRecheck(BuildContext context) {
if (settings == null && route != null) {
settings = route;
}
final match = Get.routeTree.matchRoute(settings!.name!);
final match = context.navigation.matchRoute(settings!.name!);
Get.parameters = match.parameters;
// No Match found
... ...
... ... @@ -29,7 +29,7 @@ class RouterOutlet<TDelegate extends RouterDelegate<T>, T extends Object>
final rDelegate = context.delegate as TDelegate;
var picked =
currentConfig == null ? null : pickPages(currentConfig);
if (picked?.length == 0) {
if (picked?.isEmpty ?? true) {
picked = null;
}
return pageBuilder(context, rDelegate, picked);
... ... @@ -68,7 +68,8 @@ class _RouterOutletState<TDelegate extends RouterDelegate<T>, T extends Object>
@override
void dispose() {
super.dispose();
Get.routerDelegate?.removeListener(_listener);
disposer?.call();
// Get.routerDelegate?.removeListener(_listener);
//_backButtonDispatcher.forget(_backButtonDispatcher)
}
... ... @@ -146,7 +147,7 @@ class GetRouterOutlet extends RouterOutlet<GetDelegate, RouteDecoder> {
return ret;
},
emptyPage: (delegate) =>
Get.routeTree.matchRoute(initialRoute).route ??
delegate.matchRoute(initialRoute).route ??
delegate.notFoundRoute,
key: Get.nestedKey(anchorRoute)?.navigatorKey,
delegate: delegate,
... ... @@ -162,11 +163,10 @@ class GetRouterOutlet extends RouterOutlet<GetDelegate, RouteDecoder> {
pageBuilder: (context, rDelegate, pages) {
final pageRes = <GetPage?>[
...?pages,
if (pages == null || pages.length == 0)
emptyPage?.call(rDelegate),
if (pages == null || pages.isEmpty) emptyPage?.call(rDelegate),
].whereType<GetPage>();
if (pageRes.length > 0) {
if (pageRes.isNotEmpty) {
return GetNavigator(
onPopPage: onPopPage ??
(route, result) {
... ...
void removeHash() {}
void removeLastHistory(String? url) {}
... ...
import 'dart:html';
import 'package:flutter_web_plugins/flutter_web_plugins.dart';
void removeHash() {
setUrlStrategy(PathUrlStrategy());
}
void removeLastHistory(String? url) {
window.location.replace(null);
}
... ...
... ... @@ -40,8 +40,8 @@ class GetBar extends GetSnackBar {
AnimationController? progressIndicatorController,
Color? progressIndicatorBackgroundColor,
Animation<Color>? progressIndicatorValueColor,
SnackPosition snackPosition = SnackPosition.BOTTOM,
SnackStyle snackStyle = SnackStyle.FLOATING,
SnackPosition snackPosition = SnackPosition.bottom,
SnackStyle snackStyle = SnackStyle.floating,
Curve forwardAnimationCurve = Curves.easeOutCirc,
Curve reverseAnimationCurve = Curves.easeOutCirc,
Duration animationDuration = const Duration(seconds: 1),
... ... @@ -267,8 +267,8 @@ class GetSnackBar extends StatefulWidget {
this.progressIndicatorController,
this.progressIndicatorBackgroundColor,
this.progressIndicatorValueColor,
this.snackPosition = SnackPosition.BOTTOM,
this.snackStyle = SnackStyle.FLOATING,
this.snackPosition = SnackPosition.bottom,
this.snackStyle = SnackStyle.floating,
this.forwardAnimationCurve = Curves.easeOutCirc,
this.reverseAnimationCurve = Curves.easeOutCirc,
this.animationDuration = const Duration(seconds: 1),
... ... @@ -337,16 +337,16 @@ class GetSnackBarState extends State<GetSnackBar>
return Align(
heightFactor: 1.0,
child: Material(
color: widget.snackStyle == SnackStyle.FLOATING
color: widget.snackStyle == SnackStyle.floating
? Colors.transparent
: widget.backgroundColor,
child: SafeArea(
minimum: widget.snackPosition == SnackPosition.BOTTOM
minimum: widget.snackPosition == SnackPosition.bottom
? EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom)
: EdgeInsets.only(top: MediaQuery.of(context).padding.top),
bottom: widget.snackPosition == SnackPosition.BOTTOM,
top: widget.snackPosition == SnackPosition.TOP,
bottom: widget.snackPosition == SnackPosition.bottom,
top: widget.snackPosition == SnackPosition.top,
left: false,
right: false,
child: Stack(
... ... @@ -651,10 +651,10 @@ enum RowStyle {
/// snackbar display, [SnackbarStatus.CLOSING] Starts with the closing animation
/// and ends
/// with the full snackbar dispose
enum SnackbarStatus { OPEN, CLOSED, OPENING, CLOSING }
enum SnackbarStatus { open, closed, opening, closing }
/// Indicates if snack is going to start at the [TOP] or at the [BOTTOM]
enum SnackPosition { TOP, BOTTOM }
enum SnackPosition { top, bottom }
/// Indicates if snack will be attached to the edge of the screen or not
enum SnackStyle { FLOATING, GROUNDED }
enum SnackStyle { floating, grounded }
... ...
... ... @@ -72,13 +72,13 @@ class SnackbarController {
// ignore: avoid_returning_this
void _configureAlignment(SnackPosition snackPosition) {
switch (snackbar.snackPosition) {
case SnackPosition.TOP:
case SnackPosition.top:
{
_initialAlignment = const Alignment(-1.0, -2.0);
_endAlignment = const Alignment(-1.0, -1.0);
break;
}
case SnackPosition.BOTTOM:
case SnackPosition.bottom:
{
_initialAlignment = const Alignment(-1.0, 2.0);
_endAlignment = const Alignment(-1.0, 1.0);
... ... @@ -248,7 +248,7 @@ class SnackbarController {
}
DismissDirection _getDefaultDismissDirection() {
if (snackbar.snackPosition == SnackPosition.TOP) {
if (snackbar.snackPosition == SnackPosition.top) {
return DismissDirection.up;
}
return DismissDirection.down;
... ... @@ -259,8 +259,8 @@ class SnackbarController {
direction: snackbar.dismissDirection ?? _getDefaultDismissDirection(),
resizeDuration: null,
confirmDismiss: (_) {
if (_currentStatus == SnackbarStatus.OPENING ||
_currentStatus == SnackbarStatus.CLOSING) {
if (_currentStatus == SnackbarStatus.opening ||
_currentStatus == SnackbarStatus.closing) {
return Future.value(false);
}
return Future.value(true);
... ... @@ -284,23 +284,23 @@ class SnackbarController {
void _handleStatusChanged(AnimationStatus status) {
switch (status) {
case AnimationStatus.completed:
_currentStatus = SnackbarStatus.OPEN;
_currentStatus = SnackbarStatus.open;
_snackbarStatus?.call(_currentStatus);
if (_overlayEntries.isNotEmpty) _overlayEntries.first.opaque = false;
break;
case AnimationStatus.forward:
_currentStatus = SnackbarStatus.OPENING;
_currentStatus = SnackbarStatus.opening;
_snackbarStatus?.call(_currentStatus);
break;
case AnimationStatus.reverse:
_currentStatus = SnackbarStatus.CLOSING;
_currentStatus = SnackbarStatus.closing;
_snackbarStatus?.call(_currentStatus);
if (_overlayEntries.isNotEmpty) _overlayEntries.first.opaque = false;
break;
case AnimationStatus.dismissed:
assert(!_overlayEntries.first.opaque);
_currentStatus = SnackbarStatus.CLOSED;
_currentStatus = SnackbarStatus.closed;
_snackbarStatus?.call(_currentStatus);
_removeOverlay();
break;
... ...
... ... @@ -145,7 +145,7 @@ abstract class _RxImpl<T> extends GetListenable<T> with RxObjectMixin<T> {
subject.addError(error, stackTrace);
}
Stream<R> map<R>(R mapper(T? data)) => stream.map(mapper);
Stream<R> map<R>(R Function(T? data) mapper) => stream.map(mapper);
/// Uses a callback to update [value] internally, similar to [refresh],
/// but provides the current value as the argument.
... ... @@ -167,9 +167,9 @@ abstract class _RxImpl<T> extends GetListenable<T> with RxObjectMixin<T> {
/// });
/// print( person );
/// ```
void update(void fn(T? val)) {
fn(value);
subject.add(value);
void update(T Function(T? val) fn) {
value = fn(value);
// subject.add(value);
}
/// Following certain practices on Rx data, we might want to react to certain
... ... @@ -248,18 +248,21 @@ extension RxnBoolExt on Rx<bool?> {
bool? get isFalse {
if (value != null) return !isTrue!;
return null;
}
bool? operator &(bool other) {
if (value != null) {
return other && value!;
}
return null;
}
bool? operator |(bool other) {
if (value != null) {
return other || value!;
}
return null;
}
bool? operator ^(bool other) => !other == value;
... ...
... ... @@ -269,6 +269,7 @@ extension RxnNumExt<T extends num> on Rx<T?> {
if (value != null) {
return value! * other;
}
return null;
}
/// Euclidean modulo operator.
... ... @@ -288,6 +289,7 @@ extension RxnNumExt<T extends num> on Rx<T?> {
if (value != null) {
return value! % other;
}
return null;
}
/// Division operator.
... ... @@ -295,6 +297,7 @@ extension RxnNumExt<T extends num> on Rx<T?> {
if (value != null) {
return value! / other;
}
return null;
}
/// Truncating division operator.
... ... @@ -308,6 +311,7 @@ extension RxnNumExt<T extends num> on Rx<T?> {
if (value != null) {
return value! ~/ other;
}
return null;
}
/// Negate operator.
... ... @@ -315,6 +319,7 @@ extension RxnNumExt<T extends num> on Rx<T?> {
if (value != null) {
return -value!;
}
return null;
}
/// Returns the remainder of the truncating division of `this` by [other].
... ... @@ -330,6 +335,7 @@ extension RxnNumExt<T extends num> on Rx<T?> {
if (value != null) {
return value! < other;
}
return null;
}
/// Relational less than or equal operator.
... ... @@ -337,6 +343,7 @@ extension RxnNumExt<T extends num> on Rx<T?> {
if (value != null) {
return value! <= other;
}
return null;
}
/// Relational greater than operator.
... ... @@ -344,6 +351,7 @@ extension RxnNumExt<T extends num> on Rx<T?> {
if (value != null) {
return value! > other;
}
return null;
}
/// Relational greater than or equal operator.
... ... @@ -351,6 +359,7 @@ extension RxnNumExt<T extends num> on Rx<T?> {
if (value != null) {
return value! >= other;
}
return null;
}
/// True if the number is the double Not-a-Number value; otherwise, false.
... ... @@ -585,6 +594,7 @@ class RxnNum extends Rx<num?> {
value = value! + other;
return value;
}
return null;
}
/// Subtraction operator.
... ... @@ -593,6 +603,7 @@ class RxnNum extends Rx<num?> {
value = value! - other;
return value;
}
return null;
}
}
... ... @@ -711,6 +722,7 @@ extension RxnDoubleExt on Rx<double?> {
value = value! + other;
return this;
}
return null;
}
/// Subtraction operator.
... ... @@ -719,6 +731,7 @@ extension RxnDoubleExt on Rx<double?> {
value = value! + other;
return this;
}
return null;
}
/// Multiplication operator.
... ... @@ -726,12 +739,14 @@ extension RxnDoubleExt on Rx<double?> {
if (value != null) {
return value! * other;
}
return null;
}
double? operator %(num other) {
if (value != null) {
return value! % other;
}
return null;
}
/// Division operator.
... ... @@ -739,6 +754,7 @@ extension RxnDoubleExt on Rx<double?> {
if (value != null) {
return value! / other;
}
return null;
}
/// Truncating division operator.
... ... @@ -749,6 +765,7 @@ extension RxnDoubleExt on Rx<double?> {
if (value != null) {
return value! ~/ other;
}
return null;
}
/// Negate operator. */
... ... @@ -756,6 +773,7 @@ extension RxnDoubleExt on Rx<double?> {
if (value != null) {
return -value!;
}
return null;
}
/// Returns the absolute value of this [double].
... ... @@ -1104,6 +1122,7 @@ extension RxnIntExt on Rx<int?> {
if (value != null) {
return value! & other;
}
return null;
}
/// Bit-wise or operator.
... ... @@ -1118,6 +1137,7 @@ extension RxnIntExt on Rx<int?> {
if (value != null) {
return value! | other;
}
return null;
}
/// Bit-wise exclusive-or operator.
... ... @@ -1132,6 +1152,7 @@ extension RxnIntExt on Rx<int?> {
if (value != null) {
return value! ^ other;
}
return null;
}
/// The bit-wise negate operator.
... ... @@ -1144,6 +1165,7 @@ extension RxnIntExt on Rx<int?> {
if (value != null) {
return ~value!;
}
return null;
}
/// Shift the bits of this integer to the left by [shiftAmount].
... ... @@ -1160,6 +1182,7 @@ extension RxnIntExt on Rx<int?> {
if (value != null) {
return value! << shiftAmount;
}
return null;
}
/// Shift the bits of this integer to the right by [shiftAmount].
... ... @@ -1173,6 +1196,7 @@ extension RxnIntExt on Rx<int?> {
if (value != null) {
return value! >> shiftAmount;
}
return null;
}
/// Returns this integer to the power of [exponent] modulo [modulus].
... ... @@ -1290,6 +1314,7 @@ extension RxnIntExt on Rx<int?> {
if (value != null) {
return -value!;
}
return null;
}
/// Returns the absolute value of this integer.
... ...
... ... @@ -24,7 +24,7 @@ class RxList<E> extends GetListenable<List<E>>
}
/// Generates a list of values.
factory RxList.generate(int length, E generator(int index),
factory RxList.generate(int length, E Function(int index) generator,
{bool growable = true}) {
return RxList(List.generate(length, generator, growable: growable));
}
... ... @@ -58,25 +58,25 @@ class RxList<E> extends GetListenable<List<E>>
}
@override
void add(E item) {
value.add(item);
void add(E element) {
value.add(element);
refresh();
}
@override
void addAll(Iterable<E> item) {
value.addAll(item);
void addAll(Iterable<E> iterable) {
value.addAll(iterable);
refresh();
}
@override
void removeWhere(bool test(E element)) {
void removeWhere(bool Function(E element) test) {
value.removeWhere(test);
refresh();
}
@override
void retainWhere(bool test(E element)) {
void retainWhere(bool Function(E element) test) {
value.retainWhere(test);
refresh();
}
... ... @@ -117,7 +117,7 @@ class RxList<E> extends GetListenable<List<E>>
}
@override
void sort([int compare(E a, E b)?]) {
void sort([int Function(E a, E b)? compare]) {
value.sort(compare);
refresh();
}
... ...
... ... @@ -29,8 +29,8 @@ class RxMap<K, V> extends GetListenable<Map<K, V>>
}
@override
void operator []=(K key, V val) {
value[key] = val;
void operator []=(K key, V value) {
this.value[key] = value;
refresh();
}
... ...
... ... @@ -12,7 +12,7 @@ class RxSet<E> extends GetListenable<Set<E>>
return this;
}
void update(void fn(Iterable<E>? value)) {
void update(void Function(Iterable<E>? value) fn) {
fn(value);
refresh();
}
... ... @@ -34,8 +34,8 @@ class RxSet<E> extends GetListenable<Set<E>>
}
@override
bool add(E val) {
final hasAdded = value.add(val);
bool add(E value) {
final hasAdded = this.value.add(value);
if (hasAdded) {
refresh();
}
... ... @@ -54,13 +54,13 @@ class RxSet<E> extends GetListenable<Set<E>>
int get length => value.length;
@override
E? lookup(Object? object) {
return value.lookup(object);
E? lookup(Object? element) {
return value.lookup(element);
}
@override
bool remove(Object? item) {
var hasRemoved = value.remove(item);
bool remove(Object? value) {
var hasRemoved = this.value.remove(value);
if (hasRemoved) {
refresh();
}
... ... @@ -73,8 +73,8 @@ class RxSet<E> extends GetListenable<Set<E>>
}
@override
void addAll(Iterable<E> item) {
value.addAll(item);
void addAll(Iterable<E> elements) {
value.addAll(elements);
refresh();
}
... ... @@ -97,8 +97,8 @@ class RxSet<E> extends GetListenable<Set<E>>
}
@override
void retainWhere(bool Function(E) E) {
value.retainWhere(E);
void retainWhere(bool Function(E) test) {
value.retainWhere(test);
refresh();
}
}
... ...
... ... @@ -101,11 +101,10 @@ Worker everAll(
evers.add(sub);
}
Future<void> cancel() {
Future<void> cancel() async {
for (var i in evers) {
i.cancel();
}
return Future.value(() {});
}
return Worker(cancel, '[everAll]');
... ...
... ... @@ -2,7 +2,7 @@ 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_instance/src/extension_instance.dart';
import '../../../get_instance/src/lifecycle.dart';
import '../simple/list_notifier.dart';
... ... @@ -61,17 +61,17 @@ class GetXState<T extends GetLifeCycleMixin> extends State<GetX<T>> {
@override
void initState() {
// var isPrepared = GetInstance().isPrepared<T>(tag: widget.tag);
final isRegistered = GetInstance().isRegistered<T>(tag: widget.tag);
// var isPrepared = Get.isPrepared<T>(tag: widget.tag);
final isRegistered = Get.isRegistered<T>(tag: widget.tag);
if (widget.global) {
if (isRegistered) {
_isCreator = GetInstance().isPrepared<T>(tag: widget.tag);
controller = GetInstance().find<T>(tag: widget.tag);
_isCreator = Get.isPrepared<T>(tag: widget.tag);
controller = Get.find<T>(tag: widget.tag);
} else {
controller = widget.init;
_isCreator = true;
GetInstance().put<T>(controller!, tag: widget.tag);
Get.put<T>(controller!, tag: widget.tag);
}
} else {
controller = widget.init;
... ... @@ -104,8 +104,8 @@ class GetXState<T extends GetLifeCycleMixin> extends State<GetX<T>> {
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);
if (widget.autoRemove && Get.isRegistered<T>(tag: widget.tag)) {
Get.delete<T>(tag: widget.tag);
}
}
... ...
... ... @@ -82,7 +82,7 @@ mixin StateMixin<T> on ListNotifier {
// }
}
void futurize(Future<T> Function() body(),
void futurize(Future<T> Function() Function() body,
{String? errorMessage, bool useEmpty = true}) {
final compute = body();
compute().then((newValue) {
... ... @@ -203,9 +203,9 @@ class Value<T> extends ListNotifier
return value;
}
void update(void fn(T? value)) {
fn(value);
refresh();
void update(T Function(T? value) fn) {
value = fn(value);
// refresh();
}
@override
... ... @@ -236,9 +236,8 @@ extension StateExt<T> on StateMixin<T> {
? 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 onEmpty ??
SizedBox.shrink(); // Also can be widget(null); but is risky
} else if (status.isSuccess) {
return widget(value);
} else if (status.isCustom) {
... ...
... ... @@ -119,16 +119,16 @@ class ResponsiveScreen {
double get width => context.width;
/// Is [screenType] [ScreenType.Desktop]
bool get isDesktop => (screenType == ScreenType.Desktop);
bool get isDesktop => (screenType == ScreenType.desktop);
/// Is [screenType] [ScreenType.Tablet]
bool get isTablet => (screenType == ScreenType.Tablet);
bool get isTablet => (screenType == ScreenType.tablet);
/// Is [screenType] [ScreenType.Phone]
bool get isPhone => (screenType == ScreenType.Phone);
bool get isPhone => (screenType == ScreenType.phone);
/// Is [screenType] [ScreenType.Watch]
bool get isWatch => (screenType == ScreenType.Watch);
bool get isWatch => (screenType == ScreenType.watch);
double get _getdeviceWidth {
if (_isPaltformDesktop) {
... ... @@ -139,10 +139,10 @@ class ResponsiveScreen {
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;
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
... ... @@ -165,8 +165,8 @@ class ResponsiveScreen {
}
enum ScreenType {
Watch,
Phone,
Tablet,
Desktop,
watch,
phone,
tablet,
desktop,
}
... ...
// ignore_for_file: overridden_fields
import 'package:flutter/material.dart';
import '../../../instance_manager.dart';
... ... @@ -70,6 +72,7 @@ class GetBuilder<T extends GetxController> extends StatelessWidget {
tag: tag,
dispose: dispose,
id: id,
lazy: false,
didChangeDependencies: didChangeDependencies,
didUpdateWidget: didUpdateWidget,
child: Builder(builder: (context) {
... ... @@ -114,11 +117,12 @@ abstract class Bind<T> extends StatelessWidget {
final Widget? child;
static Bind put<S>(S dependency,
{String? tag,
static Bind put<S>(
S dependency, {
String? tag,
bool permanent = false,
InstanceBuilderCallback<S>? builder}) {
Get.put<S>(dependency, tag: tag, permanent: permanent, builder: builder);
}) {
Get.put<S>(dependency, tag: tag, permanent: permanent);
return _FactoryBind<S>(
autoRemove: permanent,
assignId: true,
... ... @@ -130,10 +134,18 @@ abstract class Bind<T> extends StatelessWidget {
InstanceBuilderCallback<S> builder, {
String? tag,
bool fenix = true,
// VoidCallback? onInit,
VoidCallback? onClose,
}) {
Get.lazyPut<S>(builder, tag: tag, fenix: fenix);
return _FactoryBind<S>(
tag: tag,
// initState: (_) {
// onInit?.call();
// },
dispose: (_) {
onClose?.call();
},
);
}
... ... @@ -145,39 +157,36 @@ abstract class Bind<T> extends StatelessWidget {
);
}
static S find<S>({String? tag}) => GetInstance().find<S>(tag: tag);
static S find<S>({String? tag}) => Get.find<S>(tag: tag);
static Future<bool> delete<S>({String? tag, bool force = false}) async =>
GetInstance().delete<S>(tag: tag, force: force);
Get.delete<S>(tag: tag, force: force);
static Future<void> deleteAll({bool force = false}) async =>
GetInstance().deleteAll(force: force);
Get.deleteAll(force: force);
static void reloadAll({bool force = false}) =>
GetInstance().reloadAll(force: force);
static void reloadAll({bool force = false}) => Get.reloadAll(force: force);
static void reload<S>({String? tag, String? key, bool force = false}) =>
GetInstance().reload<S>(tag: tag, key: key, force: force);
Get.reload<S>(tag: tag, key: key, force: force);
static bool isRegistered<S>({String? tag}) =>
GetInstance().isRegistered<S>(tag: tag);
static bool isRegistered<S>({String? tag}) => Get.isRegistered<S>(tag: tag);
static bool isPrepared<S>({String? tag}) =>
GetInstance().isPrepared<S>(tag: tag);
static bool isPrepared<S>({String? tag}) => Get.isPrepared<S>(tag: tag);
static void replace<P>(P child, {String? tag}) {
final info = GetInstance().getInstanceInfo<P>(tag: tag);
final info = Get.getInstanceInfo<P>(tag: tag);
final permanent = (info.isPermanent ?? false);
delete<P>(tag: tag, force: permanent);
GetInstance().put(child, tag: tag, permanent: permanent);
Get.put(child, tag: tag, permanent: permanent);
}
static void lazyReplace<P>(InstanceBuilderCallback<P> builder,
{String? tag, bool? fenix}) {
final info = GetInstance().getInstanceInfo<P>(tag: tag);
final info = Get.getInstanceInfo<P>(tag: tag);
final permanent = (info.isPermanent ?? false);
delete<P>(tag: tag, force: permanent);
GetInstance().lazyPut(builder, tag: tag, fenix: fenix ?? permanent);
Get.lazyPut(builder, tag: tag, fenix: fenix ?? permanent);
}
factory Bind.builder({
... ... @@ -232,9 +241,9 @@ abstract class Bind<T> extends StatelessWidget {
// }
}
var widget = inheritedElement.controller;
final controller = inheritedElement.controller;
return widget;
return controller;
}
@factory
... ... @@ -335,7 +344,7 @@ class Binds extends StatelessWidget {
@override
Widget build(BuildContext context) =>
binds.reversed.fold(child, (acc, e) => e._copyWithChild(acc));
binds.reversed.fold(child, (widget, e) => e._copyWithChild(widget));
}
class Binder<T> extends InheritedWidget {
... ... @@ -350,6 +359,7 @@ class Binder<T> extends InheritedWidget {
this.global = true,
this.autoRemove = true,
this.assignId = false,
this.lazy = true,
this.initState,
this.filter,
this.tag,
... ... @@ -363,6 +373,7 @@ class Binder<T> extends InheritedWidget {
final bool global;
final Object? id;
final String? tag;
final bool lazy;
final bool autoRemove;
final bool assignId;
final Object Function(T value)? filter;
... ... @@ -419,21 +430,25 @@ class BindElement<T> extends InheritedElement {
void initState() {
widget.initState?.call(this);
var isRegistered = GetInstance().isRegistered<T>(tag: widget.tag);
var isRegistered = Get.isRegistered<T>(tag: widget.tag);
if (widget.global) {
if (isRegistered) {
if (GetInstance().isPrepared<T>(tag: widget.tag)) {
if (Get.isPrepared<T>(tag: widget.tag)) {
_isCreator = true;
} else {
_isCreator = false;
}
_controllerBuilder = () => GetInstance().find<T>(tag: widget.tag);
_controllerBuilder = () => Get.find<T>(tag: widget.tag);
} else {
_controllerBuilder = widget.init;
_isCreator = true;
GetInstance().lazyPut<T>(_controllerBuilder!, tag: widget.tag);
if (widget.lazy) {
Get.lazyPut<T>(_controllerBuilder!, tag: widget.tag);
} else {
Get.put<T>(_controllerBuilder!(), tag: widget.tag);
}
}
} else {
_controllerBuilder = widget.init;
... ... @@ -481,8 +496,8 @@ class BindElement<T> extends InheritedElement {
void dispose() {
widget.dispose?.call(this);
if (_isCreator! || widget.assignId) {
if (widget.autoRemove && GetInstance().isRegistered<T>(tag: widget.tag)) {
GetInstance().delete<T>(tag: widget.tag);
if (widget.autoRemove && Get.isRegistered<T>(tag: widget.tag)) {
Get.delete<T>(tag: widget.tag);
}
}
... ...
... ... @@ -35,7 +35,7 @@ abstract class GetView<T> extends StatelessWidget {
final String? tag = null;
T get controller => GetInstance().find<T>(tag: tag)!;
T get controller => Get.find<T>(tag: tag)!;
@override
Widget build(BuildContext context);
... ... @@ -72,7 +72,7 @@ class _GetCache<S extends GetLifeCycleMixin> extends WidgetCache<GetWidget<S>> {
InstanceInfo? info;
@override
void onInit() {
info = GetInstance().getInstanceInfo<S>(tag: widget!.tag);
info = Get.getInstanceInfo<S>(tag: widget!.tag);
_isCreator = info!.isPrepared && info!.isCreate;
... ...
... ... @@ -31,11 +31,6 @@ class GetWidgetCacheElement extends ComponentElement {
final WidgetCache<GetWidgetCache> cache;
@override
void performRebuild() {
super.performRebuild();
}
@override
void activate() {
super.activate();
markNeedsBuild();
... ...
... ... @@ -15,5 +15,6 @@ extension GetDurationUtils on Duration {
/// await 0.7.seconds.delay(() {
/// }
///```
Future delay([FutureOr callback()?]) async => Future.delayed(this, callback);
Future delay([FutureOr Function()? callback]) async =>
Future.delayed(this, callback);
}
... ...
import 'dart:async';
import '../../../get_core/src/get_interface.dart';
extension LoopEventsExt on GetInterface {
Future<T> toEnd<T>(FutureOr<T> computation()) async {
Future<T> toEnd<T>(FutureOr<T> Function() computation) async {
await Future.delayed(Duration.zero);
final val = computation();
return val;
}
FutureOr<T> asap<T>(T computation(), {bool Function()? condition}) async {
FutureOr<T> asap<T>(T Function() computation,
{bool Function()? condition}) async {
T val;
if (condition == null || !condition()) {
await Future.delayed(Duration.zero);
... ...
import 'dart:async';
import '../get_utils/get_utils.dart';
extension GetNumUtils on num {
... ... @@ -23,7 +24,7 @@ extension GetNumUtils on num {
/// print('currently running callback 1.2sec');
/// }
///```
Future delay([FutureOr callback()?]) async => Future.delayed(
Future delay([FutureOr Function()? callback]) async => Future.delayed(
Duration(milliseconds: (this * 1000).round()),
callback,
);
... ...
... ... @@ -68,7 +68,7 @@ class GetUtils {
/// "value":value==null?null:value; someVar.nil will force the null type
/// if the var is null or undefined.
/// `nil` taken from ObjC just to have a shorter sintax.
static dynamic nil(dynamic s) => s == null ? null : s;
static dynamic nil(dynamic s) => s;
/// Checks if data is null or blank (empty or only contains whitespace).
static bool? isNullOrBlank(dynamic value) {
... ... @@ -331,13 +331,6 @@ class GetUtils {
return length >= maxLength;
}
/// Checks if length of data is LOWER than maxLength.
///
/// This method is deprecated, use [isLengthLessThan] instead
@deprecated
static bool isLengthLowerThan(dynamic value, int maxLength) =>
isLengthLessThan(value, maxLength);
/// Checks if length of data is LESS than maxLength.
static bool isLengthLessThan(dynamic value, int maxLength) {
final length = _obtainDynamicLength(value);
... ... @@ -348,13 +341,6 @@ class GetUtils {
return length < maxLength;
}
/// Checks if length of data is LOWER OR EQUAL to maxLength.
///
/// This method is deprecated, use [isLengthLessOrEqual] instead
@deprecated
static bool isLengthLowerOrEqual(dynamic value, int maxLength) =>
isLengthLessOrEqual(value, maxLength);
/// Checks if length of data is LESS OR EQUAL to maxLength.
static bool isLengthLessOrEqual(dynamic value, int maxLength) {
final length = _obtainDynamicLength(value);
... ...
name: get
description: Open screens/snackbars/dialogs without context, manage states and inject dependencies easily with GetX.
version: 5.0.0-beta.30
version: 5.0.0-beta.45
homepage: https://github.com/jonataslaw/getx
environment:
sdk: '>=2.13.0 <3.0.0'
sdk: '>=2.16.0 <3.0.0'
dependencies:
flutter:
... ... @@ -15,6 +15,7 @@ dependencies:
dev_dependencies:
flutter_test:
sdk: flutter
lints: ^1.0.1
# For information on the generic Dart part of this file, see the
... ...
... ... @@ -117,7 +117,7 @@ void main() {
expect(ct1.count, 1);
ct1 = Get.find<Controller>();
expect(ct1.count, 1);
GetInstance().reload<Controller>();
Get.reload<Controller>();
ct1 = Get.find<Controller>();
expect(ct1.count, 0);
Get.reset();
... ... @@ -165,7 +165,7 @@ void main() {
test('Get.delete test with disposable controller', () async {
// Get.put(DisposableController());
expect(await Get.delete<DisposableController>(), true);
expect(Get.delete<DisposableController>(), true);
expect(() => Get.find<DisposableController>(),
throwsA(m.TypeMatcher<String>()));
});
... ...
... ... @@ -151,7 +151,7 @@ void main() {
test('Rx String with non null values', () async {
final reactiveString = Rx<String>("abc");
var currentString;
String? currentString;
reactiveString.listen((newString) {
currentString = newString;
});
... ... @@ -167,7 +167,7 @@ void main() {
test('Rx String with null values', () async {
var reactiveString = Rx<String?>(null);
var currentString;
String? currentString;
reactiveString.listen((newString) {
currentString = newString;
... ...
... ... @@ -593,11 +593,11 @@ void main() {
final currencies = [
'R\$50.58',
'\$82.48',
'\₩54.24',
'\¥81.04',
'\€4.06',
'\₹37.40',
'\₽18.12',
'₩54.24',
'¥81.04',
'€4.06',
'₹37.40',
'₽18.12',
'fr95.15',
'R81.04',
'9.35USD',
... ...
... ... @@ -10,10 +10,8 @@ class EmptyClass {}
void main() {
dynamic _id(dynamic e) => e;
Null _test;
test('null isNullOrBlank should be true for null', () {
expect(GetUtils.isNullOrBlank(_test), true);
expect(GetUtils.isNullOrBlank(null), true);
});
test('isNullOrBlank should be false for unsupported types', () {
... ...