Ahmed Fwela

Merge branch 'master' of git://github.com/jonataslaw/getx into fix-router-outlet

Showing 42 changed files with 248 additions and 175 deletions
No preview for this file type
## [4.2.3]
- Fix back button on navigator 2
- Added parameters and arguments to Get.rootDelegate
## [4.2.1]
- Remove [] from docs to try fix pub score
## [4.2.0] - Big update
This update fixes important bugs as well as integrates with Navigator 2. It also adds GetRouterOutlet, similar to angular RouterOutlet thanks to @ahmednfwela. Also, the documentation translation for Vietnamese (@khangahs) has been added, making the GetX documentation available for 11 different languages, which is just fantastic for any opensource project. GetX has achieved more than 5.4k likes from the pub, and more than 4k stars on github, has videos about it with 48k on youtube, and has communities in the 4 hemispheres of the earth, besides having a large list of contributors as you see bellow. We're all happy to facilitate development with dart and flutter, and that making programming hassle-free has been taken around the world.
... ...
... ... @@ -15,11 +15,11 @@ class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return GetMaterialApp(
return GetMaterialApp.router(
debugShowCheckedModeBanner: false,
enableLog: true,
logWriterCallback: Logger.write,
initialRoute: AppPages.INITIAL,
// initialRoute: AppPages.INITIAL,
getPages: AppPages.routes,
locale: TranslationService.locale,
fallbackLocale: TranslationService.fallbackLocale,
... ...
... ... @@ -16,6 +16,15 @@ class HomeController extends SuperController<CasesModel> {
append(() => homeRepository.getCases);
}
Country getCountryById(String id) {
final index = int.tryParse(id);
if (index != null) {
return state!.countries[index];
}
return state!.countries.first;
}
@override
void onReady() {
print('The build method is done. '
... ...
... ... @@ -33,8 +33,9 @@ class CountryView extends GetView<HomeController> {
final country = controller.state!.countries[index];
return ListTile(
onTap: () {
Get.toNamed('/home/country/details',
arguments: country);
//Get.rootDelegate.toNamed('/home/country');
Get.rootDelegate
.offNamed('/home/country/details?id=$index');
},
trailing: CircleAvatar(
backgroundImage: NetworkImage(
... ...
... ... @@ -2,13 +2,13 @@ import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../controllers/home_controller.dart';
import '../../domain/entity/cases_model.dart';
class DetailsView extends StatelessWidget {
class DetailsView extends GetView<HomeController> {
@override
Widget build(BuildContext context) {
final country = Get.arguments as Country;
final parameter = Get.rootDelegate.parameters;
final country = controller.getCountryById(parameter['id'] ?? '');
return Container(
decoration: BoxDecoration(
image: DecorationImage(
... ...
... ... @@ -71,7 +71,7 @@ class HomeView extends GetView<HomeController> {
shape: StadiumBorder(),
),
onPressed: () {
Get.toNamed('/home/country');
Get.rootDelegate.toNamed('/home/country');
},
child: Text(
'fetch_country'.tr,
... ...
... ... @@ -32,7 +32,7 @@ class LoginView extends GetView<LoginController> {
onPressed: () {
AuthService.to.login();
final thenTo = Get.rootDelegate.currentConfiguration!
.currentPage!.parameter?['then'];
.currentPage!.parameters?['then'];
Get.rootDelegate.offNamed(thenTo ?? Routes.HOME);
},
),
... ...
... ... @@ -314,7 +314,6 @@ class GetConnect extends GetConnectInterface {
final listError = res.body['errors'];
if ((listError is List) && listError.isNotEmpty) {
// return GraphQLResponse<T>(body: res.body['data'] as T);
return GraphQLResponse<T>(
graphQLErrors: listError
.map((e) => GraphQLError(
... ... @@ -350,7 +349,6 @@ class GetConnect extends GetConnectInterface {
final listError = res.body['errors'];
if ((listError is List) && listError.isNotEmpty) {
// return GraphQLResponse<T>(body: res.body['data'] as T);
return GraphQLResponse<T>(
graphQLErrors: listError
.map((e) => GraphQLError(
... ...
... ... @@ -184,7 +184,9 @@ class GetHttpClient {
String? contentType,
) {
headers['content-type'] = contentType ?? defaultContentType;
headers['user-agent'] = userAgent;
if (sendUserAgent) {
headers['user-agent'] = userAgent;
}
}
Future<Response<T>> _performRequest<T>(
... ...
... ... @@ -4,7 +4,7 @@ List<int> fileToBytes(dynamic data) {
if (data is List<int>) {
return data;
} else {
throw FormatException('File is not [File] or [String] or [List<int>]');
throw FormatException('File is not "File" or "String" or "List<int>"');
}
}
... ...
... ... @@ -7,12 +7,12 @@ List<int> fileToBytes(dynamic data) {
if (File(data).existsSync()) {
return File(data).readAsBytesSync();
} else {
throw 'File [data] not exists';
throw 'File $data not exists';
}
} else if (data is List<int>) {
return data;
} else {
throw FormatException('File is not [File] or [String] or [List<int>]');
throw FormatException('File is not "File" or "String" or "List<int>"');
}
}
... ...
... ... @@ -34,7 +34,6 @@ class HttpRequestImpl extends HttpRequestBase {
@override
Future<Response<T>> send<T>(Request<T> request) async {
var stream = request.bodyBytes.asBroadcastStream();
//var stream = BodyBytesStream.fromBytes(requestBody ?? const []);
try {
var ioRequest = (await _httpClient!.openUrl(request.method, request.url))
... ...
... ... @@ -36,7 +36,7 @@ class FormData {
/// The form fields to send for this request.
final fields = <MapEntry<String, String>>[];
/// The [files] to send for this request
/// The files to send for this request
final files = <MapEntry<String, MultipartFile>>[];
/// Returns the header string for a field. The return value is guaranteed to
... ...
... ... @@ -66,7 +66,7 @@ class Response<T> {
/// The decoded body of this [Response]. You can access the
/// body parameters as Map
/// Ex: body['title'];
/// Ex: `body['title'];`
final T? body;
}
... ... @@ -91,7 +91,7 @@ Encoding _encodingForCharset(String? charset, [Encoding fallback = utf8]) {
return Encoding.getByName(charset) ?? fallback;
}
/// Returns the [MediaType] object for the given headers's content-type.
/// Returns the MediaType object for the given headers's content-type.
///
/// Defaults to `application/octet-stream`.
HeaderValue _contentTypeForHeaders(Map<String, String> headers) {
... ...
... ... @@ -5,7 +5,7 @@
/// not being used and were not set to be permanent. In the majority
/// of the cases you will want to keep this config untouched.
/// If you new to GetX then don't change this.
/// [SmartManagement.onlyBuilders] only controllers started in init:
/// [SmartManagement.onlyBuilder] only controllers started in init:
/// or loaded into a Binding with Get.lazyPut() will be disposed. If you use
/// Get.put() or Get.putAsync() or any other approach, SmartManagement
/// will not have permissions to exclude this dependency. With the default
... ...
import 'get_instance.dart';
/// [Bindings] should be extended or implemented.
/// When using [GetMaterialApp], all [GetPage]s and navigation
/// methods (like Get.to()) have a [binding] property that takes an
/// When using `GetMaterialApp`, all `GetPage`s and navigation
/// methods (like Get.to()) have a `binding` property that takes an
/// instance of Bindings to manage the
/// dependencies() (via [Get.put()]) for the Route you are opening.
/// dependencies() (via Get.put()) for the Route you are opening.
// ignore: one_member_abstracts
abstract class Bindings {
void dependencies();
... ...
... ... @@ -3,30 +3,30 @@ import '../../route_manager.dart';
import 'get_instance.dart';
extension Inst on GetInterface {
/// Creates a new Instance<S> lazily from the [<S>builder()] callback.
/// Creates a new Instance<S> lazily from the `<S>builder()` callback.
///
/// The first time you call [Get.find()], the [builder()] callback will create
/// 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()]).
/// `Get.put()`).
///
/// Using [Get.smartManagement] as [SmartManagement.keepFactory] has
/// 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.
/// 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,
/// (`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).
/// 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);
... ... @@ -36,21 +36,21 @@ extension Inst on GetInterface {
GetInstance().printInstanceStack();
}
/// async version of [Get.put()].
/// Awaits for the resolution of the Future from [builder()] parameter and
/// 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.
/// It also registers each `instance.onClose()` with the current
/// Route `GetConfig.currentRoute` 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
/// method (`Get.create<T>()`) will be removed, but NOT the instances
/// already created by it.
/// Uses `tag` as the other methods.
///
... ... @@ -64,24 +64,24 @@ extension Inst on GetInterface {
{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()].
/// 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);
/// Injects an [Instance<S>] in memory.
/// Injects an `Instance<S>` in memory.
///
/// No need to define the generic type <[S]> as it's inferred
/// 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.
/// 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()]
/// 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,
... ... @@ -92,25 +92,25 @@ extension Inst on GetInterface {
/// Clears all registered instances (and/or tags).
/// Even the persistent ones.
///
/// - [clearFactory] clears the callbacks registered by [Get.lazyPut()]
/// - [clearFactory] clears the callbacks registered by `Get.lazyPut()`
/// - [clearRouteBindings] clears Instances associated with Routes when using
/// [GetMaterialApp].
bool reset({bool clearFactory = true, bool clearRouteBindings = true}) =>
GetInstance().reset(
clearFactory: clearFactory, clearRouteBindings: clearRouteBindings);
/// Deletes the Instance<[S]>, cleaning the memory and closes any open
/// controllers ([DisposableInterface]).
/// 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].
/// - [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);
/// Deletes all Instances, cleaning the memory and closes any open
/// controllers ([DisposableInterface]).
/// controllers (`DisposableInterface`).
///
/// - [force] Will delete the Instances even if marked as [permanent].
/// - [force] Will delete the Instances even if marked as `permanent`.
Future<void> deleteAll({bool force = false}) async =>
GetInstance().deleteAll(force: force);
... ... @@ -119,13 +119,13 @@ extension Inst on GetInterface {
void reload<S>({String? tag, String? key, bool force = false}) =>
GetInstance().reload<S>(tag: tag, key: key, force: force);
/// Checks if a Class Instance<[S]> (or [tag]) is registered in memory.
/// 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);
/// Checks if an Instance<[S]> (or [tag]) returned from a factory builder
/// [Get.lazyPut()], is registered in memory.
/// 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);
}
... ...
... ... @@ -31,19 +31,19 @@ class GetInstance {
T call<T>() => find<T>();
/// Holds references to every registered Instance when using
/// [Get.put()]
/// `Get.put()`
static final Map<String, _InstanceBuilderFactory> _singl = {};
/// Holds a reference to every registered callback when using
/// [Get.lazyPut()]
/// `Get.lazyPut()`
// static final Map<String, _Lazy> _factory = {};
/// Holds a reference to [Get.reference] when the Instance was
/// Holds a reference to `Get.reference` when the Instance was
/// created to manage the memory.
static final Map<String, String?> _routesKey = {};
/// Stores the onClose() references of instances created with [Get.create()]
/// using the [Get.reference].
/// Stores the onClose() references of instances created with `Get.create()`
/// using the `Get.reference`.
/// Experimental feature to keep the lifecycle and memory management with
/// non-singleton instances.
static final Map<String?, HashSet<Function>> _routesByCreate = {};
... ... @@ -66,8 +66,8 @@ class GetInstance {
);
}
/// async version of [Get.put()].
/// Awaits for the resolution of the Future from [builder()] parameter and
/// 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, {
... ... @@ -77,16 +77,16 @@ class GetInstance {
return put<S>(await builder(), tag: tag, permanent: permanent);
}
/// Injects an instance <[S]> in memory to be globally accessible.
/// Injects an instance `<S>` in memory to be globally accessible.
///
/// No need to define the generic type <[S]> as it's inferred from
/// 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.
/// `Get.smartManagement` rules.
S put<S>(
S dependency, {
String? tag,
... ... @@ -101,27 +101,27 @@ class GetInstance {
return find<S>(tag: tag);
}
/// Creates a new Instance<S> lazily from the [<S>builder()] callback.
/// Creates a new Instance<S> lazily from the `<S>builder()` callback.
///
/// The first time you call [Get.find()], the [builder()] callback will create
/// 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()]).
/// 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.
/// 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.
/// (`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
/// Subsequent calls to `Get.lazyPut()` with the same parameters
/// (<[S]> and optionally [tag] will **not** override the original).
void lazyPut<S>(
InstanceBuilderCallback<S> builder, {
... ... @@ -141,11 +141,11 @@ class GetInstance {
/// 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.
/// 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
/// method (`Get.create<T>()`) will be removed, but NOT the instances
/// already created by it.
///
/// Example:
... ... @@ -167,7 +167,7 @@ class GetInstance {
);
}
/// Injects the Instance [S] builder into the [_singleton] HashMap.
/// Injects the Instance [S] builder into the `_singleton` HashMap.
void _insert<S>({
bool? isSingleton,
String? name,
... ... @@ -190,9 +190,9 @@ class GetInstance {
}
/// Clears from memory registered Instances associated with [routeName] when
/// using [Get.smartManagement] as [SmartManagement.full] or
/// using `Get.smartManagement` as [SmartManagement.full] or
/// [SmartManagement.keepFactory]
/// Meant for internal usage of [GetPageRoute] and [GetDialogRoute]
/// Meant for internal usage of `GetPageRoute` and `GetDialogRoute`
void removeDependencyByRoute(String routeName) {
final keysToRemove = <String>[];
_routesKey.forEach((key, value) {
... ... @@ -201,11 +201,11 @@ class GetInstance {
}
});
/// Removes [Get.create()] instances registered in [routeName].
/// Removes `Get.create()` instances registered in `routeName`.
if (_routesByCreate.containsKey(routeName)) {
for (final onClose in _routesByCreate[routeName]!) {
// assure the [DisposableInterface] instance holding a reference
// to [onClose()] wasn't disposed.
// to onClose() wasn't disposed.
onClose();
}
_routesByCreate[routeName]!.clear();
... ... @@ -228,11 +228,11 @@ class GetInstance {
}
});
/// Removes [Get.create()] instances registered in [routeName].
/// Removes `Get.create()` instances registered in `routeName`.
if (_routesByCreate.containsKey(routeName)) {
for (final onClose in _routesByCreate[routeName]!) {
// assure the [DisposableInterface] instance holding a reference
// to [onClose()] wasn't disposed.
// to onClose() wasn't disposed.
onClose();
}
_routesByCreate[routeName]!.clear();
... ... @@ -250,8 +250,8 @@ class GetInstance {
/// 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
/// [Get.keepFactory]
/// 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
... ... @@ -273,7 +273,7 @@ class GetInstance {
}
/// Links a Class instance [S] (or [tag]) to the current route.
/// Requires usage of [GetMaterialApp].
/// Requires usage of `GetMaterialApp`.
void _registerRouteInstance<S>({String? tag}) {
_routesKey.putIfAbsent(_getKey(S, tag), () => Get.reference);
}
... ... @@ -378,7 +378,7 @@ class GetInstance {
}
/// Delete registered Class Instance [S] (or [tag]) and, closes any open
/// controllers [DisposableInterface], cleans up the memory
/// controllers `DisposableInterface`, cleans up the memory
///
/// /// Deletes the Instance<[S]>, cleaning the memory.
// ///
... ... @@ -387,12 +387,12 @@ class GetInstance {
// /// 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]).
/// 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].
/// - [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);
... ... @@ -438,9 +438,9 @@ class GetInstance {
}
/// Delete all registered Class Instances and, closes any open
/// controllers [DisposableInterface], cleans up the memory
/// controllers `DisposableInterface`, cleans up the memory
///
/// - [force] Will delete the Instances even if marked as [permanent].
/// - [force] Will delete the Instances even if marked as `permanent`.
void deleteAll({bool force = false}) {
_singl.forEach((key, value) {
delete(key: key, force: force);
... ... @@ -482,7 +482,7 @@ class GetInstance {
/// - [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
/// 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}) {
... ... @@ -506,7 +506,7 @@ typedef InjectorBuilderCallback<S> = S Function(GetInstance);
typedef AsyncInstanceBuilderCallback<S> = Future<S> Function();
/// Internal class to register instances with Get.[put]<[S]>().
/// 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]
... ... @@ -524,7 +524,7 @@ class _InstanceBuilderFactory<S> {
InstanceBuilderCallback<S> builderFunc;
/// Flag to persist the instance in memory,
/// without considering [Get.smartManagement]
/// without considering `Get.smartManagement`
bool permanent = false;
bool isInit = false;
... ...
... ... @@ -3,7 +3,7 @@ import '../../get_core/get_core.dart';
/// Special callable class to keep the contract of a regular method, and avoid
/// overrides if you extend the class that uses it, as Dart has no final
/// methods.
/// Used in [DisposableInterface] to avoid the danger of overriding onStart.
/// Used in `DisposableInterface` to avoid the danger of overriding onStart.
class InternalFinalCallback<T> {
ValueUpdater<T>? _callback;
... ...
... ... @@ -510,7 +510,7 @@ extension ExtensionBottomSheet on GetInterface {
extension GetNavigation on GetInterface {
/// **Navigation.push()** shortcut.<br><br>
///
/// Pushes a new [page] to the stack
/// Pushes a new `page` to the stack
///
/// It has the advantage of not needing context,
/// so you can call from your business logic
... ... @@ -590,7 +590,7 @@ you can only use widgets and widget functions here''';
/// **Navigation.pushNamed()** shortcut.<br><br>
///
/// Pushes a new named [page] to the stack.
/// Pushes a new named `page` to the stack.
///
/// It has the advantage of not needing context, so you can call
/// from your business logic.
... ... @@ -628,7 +628,7 @@ you can only use widgets and widget functions here''';
/// **Navigation.pushReplacementNamed()** shortcut.<br><br>
///
/// Pop the current named [page] in the stack and push a new one in its place
/// Pop the current named `page` in the stack and push a new one in its place
///
/// It has the advantage of not needing context, so you can call
/// from your business logic.
... ... @@ -684,7 +684,7 @@ you can only use widgets and widget functions here''';
/// **Navigation.pushAndRemoveUntil()** shortcut.<br><br>
///
/// Push the given [page], and then pop several pages in the stack until
/// Push the given `page`, and then pop several pages in the stack until
/// [predicate] returns true
///
/// [id] is for when you are using nested navigation,
... ... @@ -708,7 +708,7 @@ you can only use widgets and widget functions here''';
/// **Navigation.pushNamedAndRemoveUntil()** shortcut.<br><br>
///
/// Push the given named [page], and then pop several pages in the stack
/// Push the given named `page`, and then pop several pages in the stack
/// until [predicate] returns true
///
/// You can send any type of value to the other route in the [arguments].
... ... @@ -745,7 +745,7 @@ you can only use widgets and widget functions here''';
/// **Navigation.popAndPushNamed()** shortcut.<br><br>
///
/// Pop the current named page and pushes a new [page] to the stack
/// Pop the current named page and pushes a new `page` to the stack
/// in its place
///
/// You can send any type of value to the other route in the [arguments].
... ... @@ -784,7 +784,7 @@ you can only use widgets and widget functions here''';
/// **Navigation.pushNamedAndRemoveUntil()** shortcut.<br><br>
///
/// Push a named [page] and pop several pages in the stack
/// Push a named `page` and pop several pages in the stack
/// until [predicate] returns true. [predicate] is optional
///
/// It has the advantage of not needing context, so you can
... ... @@ -879,7 +879,7 @@ you can only use widgets and widget functions here''';
/// **Navigation.pushReplacement()** shortcut .<br><br>
///
/// Pop the current page and pushes a new [page] to the stack
/// Pop the current page and pushes a new `page` to the stack
///
/// It has the advantage of not needing context,
/// so you can call from your business logic
... ... @@ -936,7 +936,7 @@ you can only use widgets and widget functions here''';
/// **Navigation.pushAndRemoveUntil()** shortcut .<br><br>
///
/// Push a [page] and pop several pages in the stack
/// Push a `page` and pop several pages in the stack
/// until [predicate] returns true. [predicate] is optional
///
/// It has the advantage of not needing context,
... ...
... ... @@ -2,6 +2,22 @@ import 'package:flutter/widgets.dart';
import '../../../get.dart';
// class GetRouterState extends GetxController {
// GetRouterState({required this.currentTreeBranch});
// final List<GetPage> currentTreeBranch;
// GetPage? get currentPage => currentTreeBranch.last;
// static GetNavConfig? fromRoute(String route) {
// final res = Get.routeTree.matchRoute(route);
// if (res.treeBranch.isEmpty) return null;
// return GetNavConfig(
// currentTreeBranch: res.treeBranch,
// location: route,
// state: null,
// );
// }
// }
/// This config enables us to navigate directly to a sub-url
class GetNavConfig extends RouteInformation {
final List<GetPage> currentTreeBranch;
... ... @@ -18,7 +34,6 @@ class GetNavConfig extends RouteInformation {
GetNavConfig copyWith({
List<GetPage>? currentTreeBranch,
GetPage? currentPage,
required String? location,
required Object? state,
}) {
... ...
... ... @@ -113,6 +113,14 @@ class GetDelegate extends RouterDelegate<GetNavConfig>
return history.removeAt(index);
}
T arguments<T>() {
return currentConfiguration?.currentPage?.arguments as T;
}
Map<String, String> get parameters {
return currentConfiguration?.currentPage?.parameters ?? {};
}
// void _unsafeHistoryClear() {
// history.clear();
// }
... ... @@ -140,7 +148,7 @@ class GetDelegate extends RouterDelegate<GetNavConfig>
if (originalEntryIndex >= 0) {
switch (preventDuplicateHandlingMode) {
case PreventDuplicateHandlingMode.PopUntilOriginalRoute:
await until(config.location!, popMode: PopMode.Page);
await backUntil(config.location!, popMode: PopMode.Page);
break;
case PreventDuplicateHandlingMode.ReorderRoutes:
await _unsafeHistoryRemoveAt(originalEntryIndex);
... ... @@ -227,7 +235,7 @@ class GetDelegate extends RouterDelegate<GetNavConfig>
}
bool _canPopHistory() {
return history.length > 1;
return history.length > 0;
}
Future<bool> canPopHistory() {
... ... @@ -265,7 +273,7 @@ class GetDelegate extends RouterDelegate<GetNavConfig>
.where((r) => r.participatesInRootNavigator != null);
if (res.length == 0) {
//default behavoir, all routes participate in root navigator
return currentHistory.currentTreeBranch;
return history.map((e) => e.currentPage!).toList();
} else {
//user specified at least one participatesInRootNavigator
return res
... ... @@ -312,32 +320,45 @@ class GetDelegate extends RouterDelegate<GetNavConfig>
return route;
}
Future<void> toNamed(String fullRoute) async {
final decoder = Get.routeTree.matchRoute(fullRoute);
Future<void> toNamed(
String page, {
dynamic arguments,
Map<String, String>? parameters,
}) async {
if (parameters != null) {
final uri = Uri(path: page, queryParameters: parameters);
page = uri.toString();
}
final decoder = Get.routeTree.matchRoute(page, arguments: arguments);
decoder.replaceArguments(arguments);
return await pushHistory(
await pushHistory(
GetNavConfig(
currentTreeBranch: decoder.treeBranch,
location: fullRoute,
location: page,
state: null, //TODO: persist state?
),
);
}
Future<void> offNamed(String fullRoute) async {
Future<void> offNamed(
String page, {
dynamic arguments,
Map<String, String>? parameters,
}) async {
await popHistory();
await toNamed(fullRoute);
await toNamed(page, arguments: arguments, parameters: parameters);
}
/// Removes routes according to [PopMode]
/// until it reaches the specifc [fullRoute],
/// DOES NOT remove the [fullRoute]
Future<void> until(
Future<void> backUntil(
String fullRoute, {
PopMode popMode = PopMode.Page,
}) async {
// remove history or page entries until you meet route
var iterator = currentConfiguration;
while (_canPop(popMode) &&
iterator != null &&
... ...
... ... @@ -172,6 +172,7 @@ class GetMaterialApp extends StatelessWidget {
this.transitionDuration,
this.defaultGlobalState,
this.getPages,
this.navigatorObservers,
this.unknownRoute,
}) : routerDelegate = routerDelegate ??= Get.createDelegate(
notFoundRoute: unknownRoute,
... ... @@ -180,7 +181,7 @@ class GetMaterialApp extends StatelessWidget {
routeInformationParser ??= Get.createInformationParser(
initialRoute: getPages?.first.name ?? '/',
),
navigatorObservers = null,
//navigatorObservers = null,
navigatorKey = null,
onGenerateRoute = null,
home = null,
... ...
... ... @@ -5,10 +5,27 @@ class RouteDecoder {
final List<GetPage> treeBranch;
GetPage? get route => treeBranch.isEmpty ? null : treeBranch.last;
final Map<String, String> parameters;
final Object? arguments;
const RouteDecoder(
this.treeBranch,
this.parameters,
this.arguments,
);
void replaceArguments(Object? arguments) {
final _route = route;
if (_route != null) {
final index = treeBranch.indexOf(_route);
treeBranch[index] = _route.copy(arguments: arguments);
}
}
void replaceParameters(Object? arguments) {
final _route = route;
if (_route != null) {
final index = treeBranch.indexOf(_route);
treeBranch[index] = _route.copy(parameters: parameters);
}
}
}
class ParseRouteTree {
... ... @@ -18,7 +35,7 @@ class ParseRouteTree {
final List<GetPage> routes;
RouteDecoder matchRoute(String name) {
RouteDecoder matchRoute(String name, {Object? arguments}) {
final uri = Uri.parse(name);
// /home/profile/123 => home,profile,123 => /,/home,/home/profile,/home/profile/123
final split = uri.path.split('/').where((element) => element.isNotEmpty);
... ... @@ -53,8 +70,8 @@ class ParseRouteTree {
final mappedTreeBranch = treeBranch
.map(
(e) => e.value.copy(
parameter: {
if (e.value.parameter != null) ...e.value.parameter!,
parameters: {
if (e.value.parameters != null) ...e.value.parameters!,
...params,
},
name: e.key,
... ... @@ -64,6 +81,7 @@ class ParseRouteTree {
return RouteDecoder(
mappedTreeBranch,
params,
arguments,
);
}
... ... @@ -71,6 +89,7 @@ class ParseRouteTree {
return RouteDecoder(
treeBranch.map((e) => e.value).toList(),
params,
arguments,
);
}
... ...
... ... @@ -30,7 +30,7 @@ class PathDecoded {
class GetPage<T> extends Page<T> {
final GetPageBuilder page;
final bool? popGesture;
final Map<String, String>? parameter;
final Map<String, String>? parameters;
final String? title;
final Transition? transition;
final Curve curve;
... ... @@ -52,7 +52,7 @@ class GetPage<T> extends Page<T> {
// RouteSettings get settings => this;
@override
Object? get arguments => Get.arguments;
final Object? arguments;
@override
final String name;
... ... @@ -72,7 +72,7 @@ class GetPage<T> extends Page<T> {
this.maintainState = true,
this.curve = Curves.linear,
this.alignment,
this.parameter,
this.parameters,
this.opaque = true,
this.transitionDuration,
this.popGesture,
... ... @@ -84,6 +84,7 @@ class GetPage<T> extends Page<T> {
this.children = const <GetPage>[],
this.middlewares,
this.unknownRoute,
this.arguments,
this.preventDuplicates = true,
}) : path = _nameToRegex(name),
super(
... ... @@ -118,7 +119,7 @@ class GetPage<T> extends Page<T> {
String? name,
GetPageBuilder? page,
bool? popGesture,
Map<String, String>? parameter,
Map<String, String>? parameters,
String? title,
Transition? transition,
Curve? curve,
... ... @@ -137,6 +138,7 @@ class GetPage<T> extends Page<T> {
bool? preventDuplicates,
double? gestureWidth,
bool? participatesInRootNavigator,
Object? arguments,
}) {
return GetPage(
participatesInRootNavigator:
... ... @@ -145,7 +147,7 @@ class GetPage<T> extends Page<T> {
name: name ?? this.name,
page: page ?? this.page,
popGesture: popGesture ?? this.popGesture,
parameter: parameter ?? this.parameter,
parameters: parameters ?? this.parameters,
title: title ?? this.title,
transition: transition ?? this.transition,
curve: curve ?? this.curve,
... ... @@ -161,6 +163,7 @@ class GetPage<T> extends Page<T> {
unknownRoute: unknownRoute ?? this.unknownRoute,
middlewares: middlewares ?? this.middlewares,
gestureWidth: gestureWidth ?? this.gestureWidth,
arguments: arguments ?? this.arguments,
);
}
... ...
... ... @@ -196,7 +196,6 @@ class GetObserver extends NavigatorObserver {
value.isDialog = currentRoute.isDialog ? false : value.isDialog;
});
if (oldRoute is GetPageRoute) {
print(oldRoute.reference);
GetInstance().reloadDependencyByRoute(oldRoute.reference);
}
... ... @@ -223,7 +222,6 @@ class GetObserver extends NavigatorObserver {
});
if (route is GetPageRoute) {
print(route.reference);
GetInstance().reloadDependencyByRoute(route.reference);
}
routing?.call(_routeSend);
... ...
... ... @@ -198,7 +198,7 @@ class PageRedirect {
final _r = (isUnknown ? unknownRoute : route)!;
return GetPageRoute<T>(
page: _r.page,
parameter: _r.parameter,
parameter: _r.parameters,
settings: isUnknown
? RouteSettings(
name: _r.name,
... ... @@ -227,7 +227,7 @@ class PageRedirect {
return GetPageRoute<T>(
page: _r.page,
parameter: _r.parameter,
parameter: _r.parameters,
alignment: _r.alignment,
title: _r.title,
maintainState: _r.maintainState,
... ... @@ -279,10 +279,10 @@ class PageRedirect {
}
void addPageParameter(GetPage route) {
if (route.parameter == null) return;
if (route.parameters == null) return;
final parameters = Get.parameters;
parameters.addEntries(route.parameter!.entries);
parameters.addEntries(route.parameters!.entries);
Get.parameters = parameters;
}
}
... ...
... ... @@ -186,7 +186,7 @@ class SnackRoute<T> extends OverlayRoute<T> {
/// Called to create the animation that exposes the current progress of
/// the transition controlled by the animation controller created by
/// [createAnimationController()].
/// `createAnimationController()`.
Animation<Alignment> createAnimation() {
assert(!_transitionCompleter.isCompleted,
'Cannot reuse a $runtimeType after disposing it.');
... ...
... ... @@ -29,10 +29,10 @@ mixin RxObjectMixin<T> on NotifyManager<T> {
subject.add(value);
}
/// updates the value to [null] and adds it to the Stream.
/// updates the value to `null` and adds it to the Stream.
/// Even with null-safety coming, is still an important feature to support, as
/// [call()] doesn't accept [null] values. For instance,
/// [InputDecoration.errorText] has to be null to not show the "error state".
/// `call()` doesn't accept `null` values. For instance,
/// `InputDecoration.errorText` has to be null to not show the "error state".
///
/// Sample:
/// ```
... ... @@ -44,7 +44,7 @@ mixin RxObjectMixin<T> on NotifyManager<T> {
// }
/// Makes this Rx looks like a function so you can update a new
/// value using [rx(someOtherValue)]. Practical to assign the Rx directly
/// value using `rx(someOtherValue)`. Practical to assign the Rx directly
/// to some Widget that has a signature ::onChange( value )
///
/// Example:
... ... @@ -111,10 +111,10 @@ mixin RxObjectMixin<T> on NotifyManager<T> {
Stream<T?> get stream => subject.stream;
/// Binds an existing [Stream<T>] to this Rx<T> to keep the values in sync.
/// Binds an existing `Stream<T>` to this Rx<T> to keep the values in sync.
/// You can bind multiple sources to update the value.
/// Closing the subscription will happen automatically when the observer
/// Widget ([GetX] or [Obx]) gets unmounted from the Widget tree.
/// Widget (`GetX` or `Obx`) gets unmounted from the Widget tree.
void bindStream(Stream<T> stream) {
final listSubscriptions =
_subscriptions[subject] ??= <StreamSubscription>[];
... ...
... ... @@ -2,7 +2,7 @@ part of rx_types;
/// This class is the foundation for all reactive (Rx) classes that makes Get
/// so powerful.
/// This interface is the contract that [_RxImpl]<[T]> uses in all it's
/// This interface is the contract that _RxImpl]<T> uses in all it's
/// subclass.
abstract class RxInterface<T> {
bool get canUpdate;
... ... @@ -15,7 +15,7 @@ abstract class RxInterface<T> {
static RxInterface? proxy;
/// Calls [callback] with current value, when the value changes.
/// Calls `callback` with current value, when the value changes.
StreamSubscription<T> listen(void Function(T event) onData,
{Function? onError, void Function()? onDone, bool? cancelOnError});
... ...
... ... @@ -32,11 +32,11 @@ class Workers {
///
/// Sample:
/// Every time increment() is called, ever() will process the [condition]
/// (can be a [bool] expression or a [bool Function()]), and only call
/// (can be a [bool] expression or a `bool Function()`), and only call
/// the callback when [condition] is true.
/// In our case, only when count is bigger to 5. In order to "dispose"
/// this Worker
/// that will run forever, we made a [worker] variable. So, when the count value
/// that will run forever, we made a `worker` variable. So, when the count value
/// reaches 10, the worker gets disposed, and releases any memory resources.
///
/// ```
... ... @@ -78,7 +78,7 @@ Worker ever<T>(
/// Similar to [ever], but takes a list of [listeners], the condition
/// for the [callback] is common to all [listeners],
/// and the [callback] is executed to each one of them. The [Worker] is
/// common to all, so [worker.dispose()] will cancel all streams.
/// common to all, so `worker.dispose()` will cancel all streams.
Worker everAll(
List<RxInterface> listeners,
WorkerCallback callback, {
... ... @@ -110,10 +110,10 @@ Worker everAll(
return Worker(cancel, '[everAll]');
}
/// [once()] will execute only 1 time when [condition] is met and cancel
/// `once()` will execute only 1 time when [condition] is met and cancel
/// the subscription to the [listener] stream right after that.
/// [condition] defines when [callback] is called, and
/// can be a [bool] or a [bool Function()].
/// can be a [bool] or a `bool Function()`.
///
/// Sample:
/// ```
... ... @@ -158,7 +158,7 @@ Worker once<T>(
}
/// Ignore all changes in [listener] during [time] (1 sec by default) or until
/// [condition] is met (can be a [bool] expression or a [bool Function()]),
/// [condition] is met (can be a [bool] expression or a `bool Function()`),
/// It brings the 1st "value" since the period of time, so
/// if you click a counter button 3 times in 1 sec, it will show you "1"
/// (after 1 sec of the first press)
... ...
import 'dart:async';
/// This "function" class is the implementation of [debouncer()] Worker.
/// This "function" class is the implementation of `debouncer()` Worker.
/// It calls the function passed after specified [delay] parameter.
/// Example:
/// ```
... ...
import 'package:flutter/scheduler.dart';
import '../../get_state_manager.dart';
/// Used like [SingleTickerProviderMixin] but only with Get Controllers.
/// Used like `SingleTickerProviderMixin` but only with Get Controllers.
/// Simplifies AnimationController creation inside GetxController.
///
/// Example:
... ...
... ... @@ -9,7 +9,7 @@ import 'list_notifier.dart';
// ignore: prefer_mixin
abstract class GetxController extends DisposableInterface
with ListenableMixin, ListNotifierMixin {
/// Rebuilds [GetBuilder] each time you call [update()];
/// Rebuilds `GetBuilder` each time you call `update()`;
/// Can take a List of [ids], that will only update the matching
/// `GetBuilder( id: )`,
/// [ids] can be reused among `GetBuilders` like group tags.
... ...
... ... @@ -82,13 +82,13 @@ class ResponsiveScreenSettings {
/// When the width is greater als this value
/// the display will be set as [ScreenType.Tablet]
/// or when width greater als [watchChangePoint] and smaller als this value
/// the display will be [ScreenType.Mobile]
/// the display will be [ScreenType.Phone]
final double tabletChangePoint;
/// When the width is smaller als this value
/// the display will be set as [ScreenType.Watch]
/// or when width greater als this value and smaller als [tabletChangePoint]
/// the display will be [ScreenType.Mobile]
/// the display will be [ScreenType.Phone]
final double watchChangePoint;
const ResponsiveScreenSettings(
... ... @@ -115,7 +115,7 @@ class ResponsiveScreen {
/// Is [screenType] [ScreenType.Tablet]
bool get isTablet => (screenType == ScreenType.Tablet);
/// Is [screenType] [ScreenType.Mobile]
/// Is [screenType] [ScreenType.Phone]
bool get isPhone => (screenType == ScreenType.Phone);
/// Is [screenType] [ScreenType.Watch]
... ...
... ... @@ -4,10 +4,10 @@ import '../../../instance_manager.dart';
import '../../get_state_manager.dart';
import 'list_notifier.dart';
/// Complies with [GetStateUpdater]
/// Complies with `GetStateUpdater`
///
/// This mixin's function represents a [GetStateUpdater], and might be used
/// by [GetBuilder()], [SimpleBuilder()] (or similar) to comply
/// This mixin's function represents a `GetStateUpdater`, and might be used
/// by `GetBuilder()`, `SimpleBuilder()` (or similar) to comply
/// with [GetStateUpdate] signature. REPLACING the [StateSetter].
/// Avoids the potential (but extremely unlikely) issue of having
/// the Widget in a dispose() state, and abstracts the
... ...
... ... @@ -45,8 +45,8 @@ abstract class GetView<T> extends StatelessWidget {
/// without having to call Get.find<AwesomeController>() yourself.
/// Get save you controller on cache, so, you can to use Get.create() safely
/// GetWidget is perfect to multiples instance of a same controller. Each
/// GetWidget will have your own controller, and will be call events as [onInit]
/// and [onClose] when the controller get in/get out on memory.
/// GetWidget will have your own controller, and will be call events as `onInit`
/// and `onClose` when the controller get in/get out on memory.
abstract class GetWidget<S extends GetLifeCycleBase?> extends GetWidgetCache {
const GetWidget({Key? key}) : super(key: key);
... ...
... ... @@ -132,7 +132,7 @@ mixin ListNotifierMixin on ListenableMixin {
}
/// To dispose an [id] from future updates(), this ids are registered
/// by [GetBuilder()] or similar, so is a way to unlink the state change with
/// by `GetBuilder()` or similar, so is a way to unlink the state change with
/// the Widget from the Controller.
void disposeId(Object id) {
_updatersGroupIds!.remove(id);
... ...
... ... @@ -270,7 +270,7 @@ class GetUtils {
}
/// Checks if all data have same value.
/// Example: 111111 -> true, wwwww -> true, [1,1,1,1] -> true
/// Example: 111111 -> true, wwwww -> true, 1,1,1,1 -> true
static bool isOneAKind(dynamic value) {
if ((value is String || value is List) && !isNullOrBlank(value)!) {
final first = value[0];
... ...
name: get
description: Open screens/snackbars/dialogs without context, manage states and inject dependencies easily with GetX.
version: 4.2.0
version: 4.2.3
homepage: https://github.com/jonataslaw/getx
environment:
... ...
... ... @@ -25,7 +25,7 @@ void main() {
GetPage(
name: '/pen',
page: () => Container(),
parameter: testParams,
parameters: testParams,
),
GetPage(name: '/paper', page: () => Container()),
],
... ... @@ -48,7 +48,7 @@ void main() {
final match = tree.matchRoute(searchRoute);
expect(match, isNotNull);
expect(match.route!.name, searchRoute);
final testRouteParam = match.route!.parameter!;
final testRouteParam = match.route!.parameters!;
for (final tParam in testParams.entries) {
expect(testRouteParam[tParam.key], tParam.value);
}
... ...