Jonny Borges
Committed by GitHub

Merge branch 'master' into master

Showing 82 changed files with 2297 additions and 992 deletions

Too many changes to show.

To preserve performance only 82 of 82+ files are displayed.

No preview for this file type
... ... @@ -23,7 +23,7 @@ jobs:
# https://github.com/marketplace/actions/flutter-action
- uses: subosito/flutter-action@v2
with:
flutter-version: "3.0.5"
flutter-version: "3.7.3"
channel: "stable"
- run: flutter pub get
#- run: flutter analyze
... ...
## [5.0.0-release-candidate-2]
This version adds built-in support for animation in Flutter in an easy, clear way, and without having to create a StatefulWidget with controllers and animations. All you need to do is call the name of the animation.
If you want to add a "fadeIn" effect to any widget, simply add .fadeIn() to the end of it.
```dart
Container(
color: Colors.blue,
height: 100,
width: 100,
).fadeIn(),
```
https://user-images.githubusercontent.com/35742643/221383556-075a0b71-1617-4a31-a3c7-1acc68732f59.mp4
Maybe you want to merge two or more animations, just concatenate them at the end of the widget.
```dart
Container(
color: Colors.blue,
height: 100,
width: 100,
).fadeIn().bounce(begin: -0.8, end: 0.3),
```
https://user-images.githubusercontent.com/35742643/221383613-9044c92f-7c6b-48c4-aa79-0a0c20d4068a.mp4
Creating animation sequences in Flutter is one of the most painful things to do with the framework. You need to create tons of AnimationControllers. Well, using GetX 5 you just need to tell your animation that it is sequential. Just like that.
```dart
const FlutterLogo(size: 110)
.bounce(begin: -0.8, end: 0.4)
.fadeIn()
.spin(isSequential: true)
.wobble(isSequential: true, begin: 0, end: 8)
.flip(isSequential: true)
.fadeOut(isSequential: true),
```
Result:
https://user-images.githubusercontent.com/35742643/221393968-20cb2411-516b-44a7-8b85-45090bece532.mp4
## [5.0.0-release-candidate]
Refactor StateManager, RouteManager and InstanceManager from scratch
Fixed Bugs
Added a Scopped DI
Api now uses Navigator 2
Added new RouteOutlet
Added a new futurize method to StateMixin, that tracks updates, errors, and states programatically,
## [4.6.1]
Fix GetConnect on Flutter web
... ...
... ... @@ -1274,3 +1274,5 @@ Any contribution is welcome!
- [Flutter State Management with GetX – Complete App](https://www.appwithflutter.com/flutter-state-management-with-getx/) - by App With Flutter.
- [Flutter Routing with Animation using Get Package](https://www.appwithflutter.com/flutter-routing-using-get-package/) - by App With Flutter.
- [A minimal example on dartpad](https://dartpad.dev/2b3d0d6f9d4e312c5fdbefc414c1727e?) - by [Roi Peker](https://github.com/roipeker)
- [GetConnect: The best way to perform API operations in Flutter with Get.](https://absyz.com/getconnect-the-best-way-to-perform-api-operations-in-flutter-with-getx/) - by [MD Sarfaraj](https://github.com/socialmad)
- [How To Create an App with GetX Architect in Flutter with Get CLI](https://www.youtube.com/watch?v=7mb4qBA7kTk&t=1380s) - by [MD Sarfaraj](https://github.com/socialmad)
... ...
# Include option is buggy:
include: package:lints/recommended.yaml
include: package:flutter_lints/flutter.yaml
# In case the include issue gets fixed, lines below INCLUDE_FIX
# can be removed
... ...
... ... @@ -34,6 +34,7 @@
/android/
/web/
/macos/
/windows/
# Web related
lib/generated_plugin_registrant.dart
... ...
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.
# This file should be version controlled.
version:
revision: 7c6f9dd2396dfe7deb6fd11edc12c10786490083
channel: dev
revision: 9944297138845a94256f1cf37beb88ff9a8e811a
channel: stable
project_type: app
# Tracks metadata for the flutter migrate command
migration:
platforms:
- platform: root
create_revision: 9944297138845a94256f1cf37beb88ff9a8e811a
base_revision: 9944297138845a94256f1cf37beb88ff9a8e811a
- platform: android
create_revision: 9944297138845a94256f1cf37beb88ff9a8e811a
base_revision: 9944297138845a94256f1cf37beb88ff9a8e811a
- platform: ios
create_revision: 9944297138845a94256f1cf37beb88ff9a8e811a
base_revision: 9944297138845a94256f1cf37beb88ff9a8e811a
- platform: linux
create_revision: 9944297138845a94256f1cf37beb88ff9a8e811a
base_revision: 9944297138845a94256f1cf37beb88ff9a8e811a
- platform: macos
create_revision: 9944297138845a94256f1cf37beb88ff9a8e811a
base_revision: 9944297138845a94256f1cf37beb88ff9a8e811a
- platform: web
create_revision: 9944297138845a94256f1cf37beb88ff9a8e811a
base_revision: 9944297138845a94256f1cf37beb88ff9a8e811a
- platform: windows
create_revision: 9944297138845a94256f1cf37beb88ff9a8e811a
base_revision: 9944297138845a94256f1cf37beb88ff9a8e811a
# User provided section
# List of Local paths (relative to this file) that should be
# ignored by the migrate tool.
#
# Files that are not part of the templates will be ignored by default.
unmanaged_files:
- 'lib/main.dart'
- 'ios/Runner.xcodeproj/project.pbxproj'
... ...
# This file configures the analyzer, which statically analyzes Dart code to
# check for errors, warnings, and lints.
#
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
# invoked from the command line by running `flutter analyze`.
# The following line activates a set of recommended lints for Flutter apps,
# packages, and plugins designed to encourage good coding practices.
include: package:flutter_lints/flutter.yaml
linter:
# The lint rules applied to this project can be customized in the
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
# included above or to enable additional rules. A list of all available lints
# and their documentation is published at
# https://dart-lang.github.io/linter/lints/index.html.
#
# Instead of disabling a lint rule for the entire project in the
# section below, it can also be suppressed for a single line of code
# or a specific dart file by using the `// ignore: name_of_lint` and
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
# producing the lint.
rules:
camel_case_types: false
constant_identifier_names: false
# avoid_print: false # Uncomment to disable the `avoid_print` rule
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options
... ...
... ... @@ -6,7 +6,7 @@ import 'pt_br.dart';
class TranslationService extends Translations {
static Locale? get locale => Get.deviceLocale;
static final fallbackLocale = Locale('en', 'US');
static const fallbackLocale = Locale('en', 'US');
@override
Map<String, Map<String, String>> get keys => {
'en_US': en_US,
... ...
... ... @@ -6,7 +6,7 @@ import 'routes/app_pages.dart';
import 'shared/logger/logger_utils.dart';
void main() {
runApp(MyApp());
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
... ...
... ... @@ -10,7 +10,7 @@ class CountryView extends GetView<HomeController> {
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
decoration: const BoxDecoration(
image: DecorationImage(
fit: BoxFit.cover,
colorFilter: ColorFilter.linearToSrgbGamma(),
... ... @@ -18,38 +18,36 @@ class CountryView extends GetView<HomeController> {
"https://images.pexels.com/photos/3902882/pexels-photo-3902882.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940"))),
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 15.0, sigmaY: 15.0),
child: Container(
child: Scaffold(
child: Scaffold(
backgroundColor: Colors.transparent,
appBar: AppBar(
title: Text('corona_by_country'.tr),
backgroundColor: Colors.transparent,
appBar: AppBar(
title: Text('corona_by_country'.tr),
backgroundColor: Colors.transparent,
elevation: 0,
centerTitle: true,
),
body: Center(
child: ListView.builder(
itemCount: controller.state.countries.length,
itemBuilder: (context, index) {
final country = controller.state.countries[index];
return ListTile(
onTap: () async {
//Get.rootDelegate.toNamed('/home/country');
final data = await Get.toNamed(
'/home/country/details?id=$index');
print(data);
},
trailing: CircleAvatar(
backgroundImage: NetworkImage(
"https://flagpedia.net/data/flags/normal/${country.countryCode.toLowerCase()}.png"),
),
title: Text(country.country),
subtitle: Text(
// ignore: lines_longer_than_80_chars
'${'total_infecteds'.tr}${' ${country.totalConfirmed}'}'),
);
}),
),
elevation: 0,
centerTitle: true,
),
body: Center(
child: ListView.builder(
itemCount: controller.state.countries.length,
itemBuilder: (context, index) {
final country = controller.state.countries[index];
return ListTile(
onTap: () async {
//Get.rootDelegate.toNamed('/home/country');
final data =
await Get.toNamed('/home/country/details?id=$index');
Get.log(data);
},
trailing: CircleAvatar(
backgroundImage: NetworkImage(
"https://flagpedia.net/data/flags/normal/${country.countryCode.toLowerCase()}.png"),
),
title: Text(country.country),
subtitle: Text(
// ignore: lines_longer_than_80_chars
'${'total_infecteds'.tr}${' ${country.totalConfirmed}'}'),
);
}),
),
),
),
... ...
... ... @@ -15,77 +15,79 @@ class DetailsView extends GetView<HomeController> {
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.cover,
colorFilter: ColorFilter.linearToSrgbGamma(),
colorFilter: const ColorFilter.linearToSrgbGamma(),
image: NetworkImage(
"https://flagpedia.net/data/flags/normal/${country.countryCode.toLowerCase()}.png"),
),
),
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 15.0, sigmaY: 15.0),
child: Container(
child: Scaffold(
backgroundColor: Colors.transparent,
appBar: AppBar(
title: Text('details'.tr),
backgroundColor: Colors.black12,
elevation: 0,
centerTitle: true,
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'${country.country}',
style: TextStyle(fontSize: 45, fontWeight: FontWeight.bold),
),
SizedBox(
height: 35,
),
Text(
'total_confirmed'.tr,
style: TextStyle(
fontSize: 25,
),
),
Text(
'${country.totalConfirmed}',
style: TextStyle(fontSize: 35, fontWeight: FontWeight.bold),
),
SizedBox(
height: 10,
),
Text(
'total_deaths'.tr,
style: TextStyle(
fontSize: 25,
),
),
Text(
'${country.totalDeaths}',
style: TextStyle(fontSize: 35, fontWeight: FontWeight.bold),
),
SizedBox(
height: 10,
child: Scaffold(
backgroundColor: Colors.transparent,
appBar: AppBar(
title: Text('details'.tr),
backgroundColor: Colors.black12,
elevation: 0,
centerTitle: true,
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
country.country,
style:
const TextStyle(fontSize: 45, fontWeight: FontWeight.bold),
),
const SizedBox(
height: 35,
),
Text(
'total_confirmed'.tr,
style: const TextStyle(
fontSize: 25,
),
Text(
'total_recovered'.tr,
style: TextStyle(
fontSize: 25,
),
),
Text(
'${country.totalConfirmed}',
style:
const TextStyle(fontSize: 35, fontWeight: FontWeight.bold),
),
const SizedBox(
height: 10,
),
Text(
'total_deaths'.tr,
style: const TextStyle(
fontSize: 25,
),
Text(
'${country.totalRecovered}',
style: TextStyle(fontSize: 35, fontWeight: FontWeight.bold),
),
Text(
'${country.totalDeaths}',
style:
const TextStyle(fontSize: 35, fontWeight: FontWeight.bold),
),
const SizedBox(
height: 10,
),
Text(
'total_recovered'.tr,
style: const TextStyle(
fontSize: 25,
),
TextButton(
onPressed: () {
Get.back(result: 'djsoidjsoidj');
},
child: Text('back'))
],
)),
),
),
Text(
'${country.totalRecovered}',
style:
const TextStyle(fontSize: 35, fontWeight: FontWeight.bold),
),
TextButton(
onPressed: () {
Get.back(result: 'djsoidjsoidj');
},
child: const Text('back'))
],
)),
),
),
);
... ...
... ... @@ -9,7 +9,7 @@ class HomeView extends GetView<HomeController> {
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
decoration: const BoxDecoration(
color: Colors.white,
image: DecorationImage(
fit: BoxFit.cover,
... ... @@ -22,7 +22,7 @@ class HomeView extends GetView<HomeController> {
backgroundColor: Colors.transparent,
appBar: AppBar(
leading: IconButton(
icon: Icon(Icons.add),
icon: const Icon(Icons.add),
onPressed: () {
Get.snackbar('title', 'message');
},
... ... @@ -38,43 +38,45 @@ class HomeView extends GetView<HomeController> {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(
const SizedBox(
height: 100,
),
Text(
'total_confirmed'.tr,
style: TextStyle(
style: const TextStyle(
fontSize: 30,
),
),
Text(
'${state!.global.totalConfirmed}',
style: TextStyle(fontSize: 45, fontWeight: FontWeight.bold),
style: const TextStyle(
fontSize: 45, fontWeight: FontWeight.bold),
),
SizedBox(
const SizedBox(
height: 10,
),
Text(
'total_deaths'.tr,
style: TextStyle(
style: const TextStyle(
fontSize: 30,
),
),
Text(
'${state.global.totalDeaths}',
style: TextStyle(fontSize: 45, fontWeight: FontWeight.bold),
style: const TextStyle(
fontSize: 45, fontWeight: FontWeight.bold),
),
SizedBox(
const SizedBox(
height: 10,
),
OutlinedButton(
style: OutlinedButton.styleFrom(
textStyle: TextStyle(color: Colors.black),
side: BorderSide(
textStyle: const TextStyle(color: Colors.black),
side: const BorderSide(
color: Colors.deepPurple,
width: 3,
),
shape: StadiumBorder(),
shape: const StadiumBorder(),
),
onPressed: () async {
//await Navigation Get.rootDelegate.toNamed('/home/country');
... ... @@ -82,7 +84,7 @@ class HomeView extends GetView<HomeController> {
},
child: Text(
'fetch_country'.tr,
style: TextStyle(
style: const TextStyle(
fontWeight: FontWeight.bold,
color: Colors.black,
),
... ... @@ -90,17 +92,17 @@ class HomeView extends GetView<HomeController> {
),
OutlinedButton(
style: OutlinedButton.styleFrom(
textStyle: TextStyle(color: Colors.black),
side: BorderSide(
textStyle: const TextStyle(color: Colors.black),
side: const BorderSide(
color: Colors.deepPurple,
width: 3,
),
shape: StadiumBorder(),
shape: const StadiumBorder(),
),
onPressed: () {
Get.updateLocale(Locale('pt', 'BR'));
Get.updateLocale(const Locale('pt', 'BR'));
},
child: Text(
child: const Text(
'Update language to Portuguese',
style: TextStyle(
fontWeight: FontWeight.bold,
... ...
... ... @@ -14,16 +14,16 @@ class AppPages {
static final routes = [
GetPage(
name: Routes.HOME,
page: () => HomeView(),
page: () => const HomeView(),
binding: HomeBinding(),
children: [
GetPage(
name: Routes.COUNTRY,
page: () => CountryView(),
page: () => const CountryView(),
children: [
GetPage(
name: Routes.DETAILS,
page: () => DetailsView(),
page: () => const DetailsView(),
),
],
),
... ...
mixin Logger {
// Sample of abstract logging function
static void write(String text, {bool isError = false}) {
// ignore: avoid_print
Future.microtask(() => print('** $text. isError: [$isError]'));
}
}
... ...
... ... @@ -38,6 +38,7 @@ dev_dependencies:
flutter_test:
sdk: flutter
get_test: 4.0.1
flutter_lints: ^2.0.1
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec
... ...
... ... @@ -3,13 +3,11 @@ import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:get/get.dart';
import 'package:get_demo/pages/home/domain/adapters/repository_adapter.dart';
import 'package:get_demo/pages/home/domain/entity/cases_model.dart';
import 'package:get_demo/pages/home/presentation/controllers/home_controller.dart';
// import 'package:get_demo/routes/app_pages.dart';
// import 'package:get_test/get_test.dart';
import 'package:matcher/matcher.dart' as m;
import '../lib/pages/home/domain/adapters/repository_adapter.dart';
import '../lib/pages/home/domain/entity/cases_model.dart';
import '../lib/pages/home/presentation/controllers/home_controller.dart';
class MockRepositorySuccess implements IHomeRepository {
@override
... ... @@ -57,7 +55,7 @@ void main() {
test('Test Controller', () async {
/// Controller can't be on memory
expect(() => Get.find<HomeController>(tag: 'success'),
throwsA(m.TypeMatcher<String>()));
throwsA(const TypeMatcher<String>()));
/// binding will put the controller on memory
binding.dependencies();
... ... @@ -72,7 +70,7 @@ void main() {
expect(controller.status.isLoading, true);
/// await time request
await Future.delayed(Duration(milliseconds: 100));
await Future.delayed(const Duration(milliseconds: 100));
/// test if status is success
expect(controller.status.isSuccess, true);
... ...
// This is a generated file; do not edit or check into version control.
FLUTTER_ROOT=/Users/jonatasborges/flutter
FLUTTER_APPLICATION_PATH=/Users/jonatasborges/consertar/getx/example_nav2
FLUTTER_APPLICATION_PATH=/Users/jonatasborges/getx-parse/getx/example_nav2
COCOAPODS_PARALLEL_CODE_SIGN=true
FLUTTER_TARGET=/Users/jonatasborges/consertar/getx/example_nav2/lib/main.dart
FLUTTER_TARGET=lib/main.dart
FLUTTER_BUILD_DIR=build
FLUTTER_BUILD_NAME=1.0.0
FLUTTER_BUILD_NUMBER=1
EXCLUDED_ARCHS[sdk=iphonesimulator*]=i386
EXCLUDED_ARCHS[sdk=iphoneos*]=armv7
DART_DEFINES=RkxVVFRFUl9XRUJfQVVUT19ERVRFQ1Q9dHJ1ZQ==
DART_OBFUSCATION=false
TRACK_WIDGET_CREATION=true
TREE_SHAKE_ICONS=false
PACKAGE_CONFIG=/Users/jonatasborges/consertar/getx/example_nav2/.dart_tool/package_config.json
PACKAGE_CONFIG=.dart_tool/package_config.json
... ...
#!/bin/sh
# This is a generated file; do not edit or check into version control.
export "FLUTTER_ROOT=/Users/jonatasborges/flutter"
export "FLUTTER_APPLICATION_PATH=/Users/jonatasborges/consertar/getx/example_nav2"
export "FLUTTER_APPLICATION_PATH=/Users/jonatasborges/getx-parse/getx/example_nav2"
export "COCOAPODS_PARALLEL_CODE_SIGN=true"
export "FLUTTER_TARGET=/Users/jonatasborges/consertar/getx/example_nav2/lib/main.dart"
export "FLUTTER_TARGET=lib/main.dart"
export "FLUTTER_BUILD_DIR=build"
export "FLUTTER_BUILD_NAME=1.0.0"
export "FLUTTER_BUILD_NUMBER=1"
export "DART_DEFINES=RkxVVFRFUl9XRUJfQVVUT19ERVRFQ1Q9dHJ1ZQ=="
export "DART_OBFUSCATION=false"
export "TRACK_WIDGET_CREATION=true"
export "TREE_SHAKE_ICONS=false"
export "PACKAGE_CONFIG=/Users/jonatasborges/consertar/getx/example_nav2/.dart_tool/package_config.json"
export "PACKAGE_CONFIG=.dart_tool/package_config.json"
... ...
... ... @@ -8,7 +8,7 @@ class DashboardController extends GetxController {
void onReady() {
super.onReady();
Timer.periodic(
Duration(seconds: 1),
const Duration(seconds: 1),
(timer) {
now.value = DateTime.now();
},
... ...
... ... @@ -4,6 +4,8 @@ import 'package:get/get.dart';
import '../controllers/dashboard_controller.dart';
class DashboardView extends GetView<DashboardController> {
const DashboardView({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
... ... @@ -12,7 +14,7 @@ class DashboardView extends GetView<DashboardController> {
() => Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
const Text(
'DashboardView is working',
style: TextStyle(fontSize: 20),
),
... ...
... ... @@ -14,7 +14,6 @@ class HomeView extends GetView<HomeController> {
final delegate = context.navigation;
//This router outlet handles the appbar and the bottom navigation bar
final currentLocation = context.location;
print(currentLocation);
var currentIndex = 0;
if (currentLocation.startsWith(Routes.products) == true) {
currentIndex = 2;
... ... @@ -46,7 +45,7 @@ class HomeView extends GetView<HomeController> {
default:
}
},
items: [
items: const [
// _Paths.HOME + [Empty]
BottomNavigationBarItem(
icon: Icon(Icons.home),
... ...
... ... @@ -6,6 +6,8 @@ import '../../../routes/app_pages.dart';
import '../controllers/login_controller.dart';
class LoginView extends GetView<LoginController> {
const LoginView({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
... ... @@ -25,7 +27,7 @@ class LoginView extends GetView<LoginController> {
},
),
MaterialButton(
child: Text(
child: const Text(
'Do LOGIN !!',
style: TextStyle(color: Colors.blue, fontSize: 20),
),
... ...
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../controllers/product_details_controller.dart';
class ProductDetailsView extends GetWidget<ProductDetailsController> {
const ProductDetailsView({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
... ... @@ -12,7 +13,7 @@ class ProductDetailsView extends GetWidget<ProductDetailsController> {
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
const Text(
'ProductDetailsView is working',
style: TextStyle(fontSize: 20),
),
... ...
... ... @@ -11,13 +11,13 @@ class ProductsView extends GetView<ProductsController> {
return Scaffold(
floatingActionButton: FloatingActionButton.extended(
onPressed: () => controller.loadDemoProductsFromSomeWhere(),
label: Text('Add'),
label: const Text('Add'),
),
body: Column(
children: [
Hero(
const Hero(
tag: 'heroLogo',
child: const FlutterLogo(),
child: FlutterLogo(),
),
Expanded(
child: Obx(
... ...
... ... @@ -5,6 +5,8 @@ import '../../../routes/app_pages.dart';
import '../controllers/profile_controller.dart';
class ProfileView extends GetView<ProfileController> {
const ProfileView({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
... ... @@ -13,16 +15,16 @@ class ProfileView extends GetView<ProfileController> {
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
const Text(
'ProfileView is working',
style: TextStyle(fontSize: 20),
),
Hero(
const Hero(
tag: 'heroLogo',
child: const FlutterLogo(),
child: FlutterLogo(),
),
MaterialButton(
child: Text('Show a test dialog'),
child: const Text('Show a test dialog'),
onPressed: () {
//shows a dialog
Get.defaultDialog(
... ... @@ -32,7 +34,7 @@ class ProfileView extends GetView<ProfileController> {
},
),
MaterialButton(
child: Text('Show a test dialog in Home router outlet'),
child: const Text('Show a test dialog in Home router outlet'),
onPressed: () {
//shows a dialog
... ...
... ... @@ -10,11 +10,6 @@ class RootController extends GetxController {
}
@override
void onReady() {
super.onReady();
}
@override
void onClose() {}
void increment() => count.value++;
}
... ...
... ... @@ -19,7 +19,7 @@ class DrawerWidget extends StatelessWidget {
color: Colors.red,
),
ListTile(
title: Text('Home'),
title: const Text('Home'),
onTap: () {
Get.toNamed(Routes.home);
//to close the drawer
... ... @@ -28,7 +28,7 @@ class DrawerWidget extends StatelessWidget {
},
),
ListTile(
title: Text('Settings'),
title: const Text('Settings'),
onTap: () {
Get.toNamed(Routes.settings);
//to close the drawer
... ... @@ -38,7 +38,7 @@ class DrawerWidget extends StatelessWidget {
),
if (AuthService.to.isLoggedInValue)
ListTile(
title: Text(
title: const Text(
'Logout',
style: TextStyle(
color: Colors.red,
... ... @@ -54,7 +54,7 @@ class DrawerWidget extends StatelessWidget {
),
if (!AuthService.to.isLoggedInValue)
ListTile(
title: Text(
title: const Text(
'Login',
style: TextStyle(
color: Colors.blue,
... ...
... ... @@ -6,6 +6,8 @@ import '../controllers/root_controller.dart';
import 'drawer.dart';
class RootView extends GetView<RootController> {
const RootView({super.key});
@override
Widget build(BuildContext context) {
return RouterOutlet.builder(
... ... @@ -13,7 +15,7 @@ class RootView extends GetView<RootController> {
builder: (context) {
final title = context.location;
return Scaffold(
drawer: DrawerWidget(),
drawer: const DrawerWidget(),
appBar: AppBar(
title: Text(title),
centerTitle: true,
... ...
... ... @@ -10,11 +10,6 @@ class SettingsController extends GetxController {
}
@override
void onReady() {
super.onReady();
}
@override
void onClose() {}
void increment() => count.value++;
}
... ...
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../controllers/settings_controller.dart';
class SettingsView extends GetView<SettingsController> {
const SettingsView({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
return const Scaffold(
body: Center(
child: Text(
'SettingsView is working',
... ...
... ... @@ -18,11 +18,11 @@ class SplashService extends GetxService {
Future<void> _initFunction() async {
final t = Timer.periodic(
Duration(milliseconds: 500),
const Duration(milliseconds: 500),
(t) => _changeActiveString(),
);
//simulate some long running operation
await Future.delayed(Duration(seconds: 5));
await Future.delayed(const Duration(seconds: 5));
//cancel the timer once we are done
t.cancel();
}
... ...
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../controllers/splash_service.dart';
class SplashView extends GetView<SplashService> {
const SplashView({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
... ... @@ -15,10 +16,10 @@ class SplashView extends GetView<SplashService> {
Obx(
() => Text(
controller.welcomeStr[controller.activeStr.value],
style: TextStyle(fontSize: 20),
style: const TextStyle(fontSize: 20),
),
),
CircularProgressIndicator(),
const CircularProgressIndicator(),
],
),
),
... ...
... ... @@ -28,7 +28,7 @@ class AppPages {
static final routes = [
GetPage(
name: '/',
page: () => RootView(),
page: () => const RootView(),
bindings: [RootBinding()],
participatesInRootNavigator: true,
preventDuplicates: true,
... ... @@ -39,7 +39,7 @@ class AppPages {
EnsureNotAuthedMiddleware(),
],
name: _Paths.login,
page: () => LoginView(),
page: () => const LoginView(),
bindings: [LoginBinding()],
),
GetPage(
... ... @@ -53,7 +53,7 @@ class AppPages {
children: [
GetPage(
name: _Paths.dashboard,
page: () => DashboardView(),
page: () => const DashboardView(),
bindings: [
DashboardBinding(),
],
... ... @@ -64,7 +64,7 @@ class AppPages {
EnsureAuthMiddleware(),
],
name: _Paths.profile,
page: () => ProfileView(),
page: () => const ProfileView(),
title: 'Profile',
transition: Transition.size,
bindings: [ProfileBinding()],
... ... @@ -82,8 +82,8 @@ class AppPages {
name: _Paths.productDetails,
transition: Transition.cupertino,
showCupertinoParallax: true,
page: () => ProductDetailsView(),
bindings: [],
page: () => const ProductDetailsView(),
bindings: const [],
middlewares: [
//only enter this route when authed
EnsureAuthMiddleware(),
... ... @@ -95,7 +95,7 @@ class AppPages {
),
GetPage(
name: _Paths.settings,
page: () => SettingsView(),
page: () => const SettingsView(),
bindings: [
SettingsBinding(),
],
... ...
... ... @@ -3,6 +3,7 @@
/// injection, and route management in a quick and practical way.
library get;
export 'get_animations/index.dart';
export 'get_common/get_reset.dart';
export 'get_connect/connect.dart';
export 'get_core/get_core.dart';
... ...
import 'dart:math';
import 'dart:ui';
import 'package:flutter/widgets.dart';
import 'get_animated_builder.dart';
typedef OffsetBuilder = Offset Function(BuildContext, double);
class FadeInAnimation extends OpacityAnimation {
FadeInAnimation({
super.key,
required super.duration,
required super.delay,
required super.child,
super.onComplete,
super.begin = 0,
super.end = 1,
super.idleValue = 0,
});
}
class FadeOutAnimation extends OpacityAnimation {
FadeOutAnimation({
super.key,
required super.duration,
required super.delay,
required super.child,
super.onComplete,
super.begin = 1,
super.end = 0,
super.idleValue = 1,
});
}
class OpacityAnimation extends GetAnimatedBuilder<double> {
OpacityAnimation({
super.key,
required super.duration,
required super.delay,
required super.child,
required super.onComplete,
required double begin,
required double end,
required super.idleValue,
}) : super(
tween: Tween<double>(begin: begin, end: end),
builder: (context, value, child) {
return Opacity(
opacity: value,
child: child!,
);
},
);
}
class RotateAnimation extends GetAnimatedBuilder<double> {
RotateAnimation({
super.key,
required super.duration,
required super.delay,
required super.child,
super.onComplete,
required double begin,
required double end,
super.idleValue = 0,
}) : super(
builder: (context, value, child) => Transform.rotate(
angle: value,
child: child,
),
tween: Tween<double>(begin: begin, end: end),
);
}
class ScaleAnimation extends GetAnimatedBuilder<double> {
ScaleAnimation({
super.key,
required super.duration,
required super.delay,
required super.child,
super.onComplete,
required double begin,
required double end,
super.idleValue = 0,
}) : super(
builder: (context, value, child) => Transform.scale(
scale: value,
child: child,
),
tween: Tween<double>(begin: begin, end: end),
);
}
// class SlideAnimation extends GetAnimatedBuilder<Offset> {
// SlideAnimation({
// super.key,
// required super.duration,
// required super.delay,
// required super.child,
// super.onComplete,
// required Offset begin,
// required Offset end,
// super.idleValue = const Offset(0, 0),
// }) : super(
// builder: (context, value, child) => Transform.translate(
// offset: value,
// child: child,
// ),
// tween: Tween(begin: begin, end: end),
// );
// }
class BounceAnimation extends GetAnimatedBuilder<double> {
BounceAnimation({
super.key,
required super.duration,
required super.delay,
required super.child,
super.onComplete,
super.curve = Curves.bounceOut,
required double begin,
required double end,
super.idleValue = 0,
}) : super(
builder: (context, value, child) => Transform.scale(
scale: 1 + value.abs(),
child: child,
),
tween: Tween<double>(begin: begin, end: end),
);
}
class SpinAnimation extends GetAnimatedBuilder<double> {
SpinAnimation({
super.key,
required super.duration,
required super.delay,
required super.child,
super.onComplete,
super.idleValue = 0,
}) : super(
builder: (context, value, child) => Transform.rotate(
angle: value * pi / 180.0,
child: child,
),
tween: Tween<double>(begin: 0, end: 360),
);
}
class SizeAnimation extends GetAnimatedBuilder<double> {
SizeAnimation({
super.key,
required super.duration,
required super.delay,
required super.child,
super.onComplete,
super.idleValue = 0,
required double begin,
required double end,
}) : super(
builder: (context, value, child) => Transform.scale(
scale: value,
child: child,
),
tween: Tween<double>(begin: begin, end: end),
);
}
class BlurAnimation extends GetAnimatedBuilder<double> {
BlurAnimation({
super.key,
required super.duration,
required super.delay,
required super.child,
super.onComplete,
required double begin,
required double end,
super.idleValue = 0,
}) : super(
builder: (context, value, child) => BackdropFilter(
filter: ImageFilter.blur(
sigmaX: value,
sigmaY: value,
),
child: child,
),
tween: Tween<double>(begin: begin, end: end),
);
}
class FlipAnimation extends GetAnimatedBuilder<double> {
FlipAnimation({
super.key,
required super.duration,
required super.delay,
required super.child,
super.onComplete,
required double begin,
required double end,
super.idleValue = 0,
}) : super(
builder: (context, value, child) {
final radians = value * pi;
return Transform(
transform: Matrix4.rotationY(radians),
alignment: Alignment.center,
child: child,
);
},
tween: Tween<double>(begin: begin, end: end),
);
}
class WaveAnimation extends GetAnimatedBuilder<double> {
WaveAnimation({
super.key,
required super.duration,
required super.delay,
required super.child,
super.onComplete,
required double begin,
required double end,
super.idleValue = 0,
}) : super(
builder: (context, value, child) => Transform(
transform: Matrix4.translationValues(
0.0,
20.0 * sin(value * pi * 2),
0.0,
),
child: child,
),
tween: Tween<double>(begin: begin, end: end),
);
}
class WobbleAnimation extends GetAnimatedBuilder<double> {
WobbleAnimation({
super.key,
required super.duration,
required super.delay,
required super.child,
super.onComplete,
required double begin,
required double end,
super.idleValue = 0,
}) : super(
builder: (context, value, child) => Transform(
transform: Matrix4.identity()
..setEntry(3, 2, 0.001)
..rotateZ(sin(value * pi * 2) * 0.1),
alignment: Alignment.center,
child: child,
),
tween: Tween<double>(begin: begin, end: end),
);
}
class SlideInLeftAnimation extends SlideAnimation {
SlideInLeftAnimation({
super.key,
required super.duration,
required super.delay,
required super.child,
super.onComplete,
required super.begin,
required super.end,
super.idleValue = 0,
}) : super(
offsetBuild: (context, value) =>
Offset(value * MediaQuery.of(context).size.width, 0),
);
}
class SlideInRightAnimation extends SlideAnimation {
SlideInRightAnimation({
super.key,
required super.duration,
required super.delay,
required super.child,
super.onComplete,
required super.begin,
required super.end,
super.idleValue = 0,
}) : super(
offsetBuild: (context, value) =>
Offset((1 - value) * MediaQuery.of(context).size.width, 0),
);
}
class SlideInUpAnimation extends SlideAnimation {
SlideInUpAnimation({
super.key,
required super.duration,
required super.delay,
required super.child,
super.onComplete,
required super.begin,
required super.end,
super.idleValue = 0,
}) : super(
offsetBuild: (context, value) =>
Offset(0, value * MediaQuery.of(context).size.height),
);
}
class SlideInDownAnimation extends SlideAnimation {
SlideInDownAnimation({
super.key,
required super.duration,
required super.delay,
required super.child,
super.onComplete,
required super.begin,
required super.end,
super.idleValue = 0,
}) : super(
offsetBuild: (context, value) =>
Offset(0, (1 - value) * MediaQuery.of(context).size.height),
);
}
class SlideAnimation extends GetAnimatedBuilder<double> {
SlideAnimation({
super.key,
required super.duration,
required super.delay,
required super.child,
required double begin,
required double end,
required OffsetBuilder offsetBuild,
super.onComplete,
super.idleValue = 0,
}) : super(
builder: (context, value, child) => Transform.translate(
offset: offsetBuild(context, value),
child: child,
),
tween: Tween<double>(begin: begin, end: end),
);
}
// class ZoomAnimation extends GetAnimatedBuilder<double> {
// ZoomAnimation({
// super.key,
// required super.duration,
// required super.delay,
// required super.child,
// super.onComplete,
// required double begin,
// required double end,
// super.idleValue = 0,
// }) : super(
// builder: (context, value, child) => Transform.scale(
// scale: lerpDouble(1, end, value)!,
// child: child,
// ),
// tween: Tween<double>(begin: begin, end: end),
// );
// }
class ColorAnimation extends GetAnimatedBuilder<Color?> {
ColorAnimation({
super.key,
required super.duration,
required super.delay,
required super.child,
super.onComplete,
required Color begin,
required Color end,
Color? idleColor,
}) : super(
builder: (context, value, child) => ColorFiltered(
colorFilter: ColorFilter.mode(
Color.lerp(begin, end, value!.value.toDouble())!,
BlendMode.srcIn,
),
child: child,
),
idleValue: idleColor ?? begin,
tween: ColorTween(begin: begin, end: end),
);
}
... ...
import 'package:flutter/material.dart';
import 'animations.dart';
import 'get_animated_builder.dart';
const _defaultDuration = Duration(seconds: 2);
const _defaultDelay = Duration.zero;
extension AnimationExtension on Widget {
GetAnimatedBuilder? get _currentAnimation =>
(this is GetAnimatedBuilder) ? this as GetAnimatedBuilder : null;
GetAnimatedBuilder fadeIn({
Duration duration = _defaultDuration,
Duration delay = _defaultDelay,
ValueSetter<AnimationController>? onComplete,
bool isSequential = false,
}) {
assert(isSequential || this is! FadeOutAnimation,
'Can not use fadeOut + fadeIn when isSequential is false');
return FadeInAnimation(
duration: duration,
delay: _getDelay(isSequential, delay),
onComplete: onComplete,
child: this,
);
}
GetAnimatedBuilder fadeOut({
Duration duration = _defaultDuration,
Duration delay = _defaultDelay,
ValueSetter<AnimationController>? onComplete,
bool isSequential = false,
}) {
assert(isSequential || this is! FadeInAnimation,
'Can not use fadeOut() + fadeIn when isSequential is false');
return FadeOutAnimation(
duration: duration,
delay: _getDelay(isSequential, delay),
onComplete: onComplete,
child: this,
);
}
GetAnimatedBuilder rotate({
required double begin,
required double end,
Duration duration = _defaultDuration,
Duration delay = _defaultDelay,
ValueSetter<AnimationController>? onComplete,
bool isSequential = false,
}) {
return RotateAnimation(
duration: duration,
delay: _getDelay(isSequential, delay),
begin: begin,
end: end,
onComplete: onComplete,
child: this,
);
}
GetAnimatedBuilder scale({
required double begin,
required double end,
Duration duration = _defaultDuration,
Duration delay = _defaultDelay,
ValueSetter<AnimationController>? onComplete,
bool isSequential = false,
}) {
return ScaleAnimation(
duration: duration,
delay: _getDelay(isSequential, delay),
begin: begin,
end: end,
onComplete: onComplete,
child: this,
);
}
GetAnimatedBuilder slide({
required OffsetBuilder offset,
double begin = 0,
double end = 1,
Duration duration = _defaultDuration,
Duration delay = _defaultDelay,
ValueSetter<AnimationController>? onComplete,
bool isSequential = false,
}) {
return SlideAnimation(
duration: duration,
delay: _getDelay(isSequential, delay),
begin: begin,
end: end,
onComplete: onComplete,
offsetBuild: offset,
child: this,
);
}
GetAnimatedBuilder bounce({
required double begin,
required double end,
Duration duration = _defaultDuration,
Duration delay = _defaultDelay,
ValueSetter<AnimationController>? onComplete,
bool isSequential = false,
}) {
return BounceAnimation(
duration: duration,
delay: _getDelay(isSequential, delay),
begin: begin,
end: end,
onComplete: onComplete,
child: this,
);
}
GetAnimatedBuilder spin({
Duration duration = _defaultDuration,
Duration delay = _defaultDelay,
ValueSetter<AnimationController>? onComplete,
bool isSequential = false,
}) {
return SpinAnimation(
duration: duration,
delay: _getDelay(isSequential, delay),
onComplete: onComplete,
child: this,
);
}
GetAnimatedBuilder size({
required double begin,
required double end,
Duration duration = _defaultDuration,
Duration delay = _defaultDelay,
ValueSetter<AnimationController>? onComplete,
bool isSequential = false,
}) {
return SizeAnimation(
duration: duration,
delay: _getDelay(isSequential, delay),
begin: begin,
end: end,
onComplete: onComplete,
child: this,
);
}
GetAnimatedBuilder blur({
double begin = 0,
double end = 15,
Duration duration = _defaultDuration,
Duration delay = _defaultDelay,
ValueSetter<AnimationController>? onComplete,
bool isSequential = false,
}) {
return BlurAnimation(
duration: duration,
delay: _getDelay(isSequential, delay),
begin: begin,
end: end,
onComplete: onComplete,
child: this,
);
}
GetAnimatedBuilder flip({
double begin = 0,
double end = 1,
Duration duration = _defaultDuration,
Duration delay = _defaultDelay,
ValueSetter<AnimationController>? onComplete,
bool isSequential = false,
}) {
return FlipAnimation(
duration: duration,
delay: _getDelay(isSequential, delay),
begin: begin,
end: end,
onComplete: onComplete,
child: this,
);
}
GetAnimatedBuilder wave({
double begin = 0,
double end = 1,
Duration duration = _defaultDuration,
Duration delay = _defaultDelay,
ValueSetter<AnimationController>? onComplete,
bool isSequential = false,
}) {
return WaveAnimation(
duration: duration,
delay: _getDelay(isSequential, delay),
begin: begin,
end: end,
onComplete: onComplete,
child: this,
);
}
Duration _getDelay(bool isSequential, Duration delay) {
assert(!(isSequential && delay != Duration.zero),
"Error: When isSequential is true, delay must be non-zero. Context: isSequential: $isSequential delay: $delay");
return isSequential
? (_currentAnimation?.totalDuration ?? Duration.zero)
: delay;
}
}
... ...
import 'package:flutter/material.dart';
import 'animations.dart';
class GetAnimatedBuilder<T> extends StatefulWidget {
final Duration duration;
final Duration delay;
final Widget child;
final ValueSetter<AnimationController>? onComplete;
final ValueSetter<AnimationController>? onStart;
final Tween<T> tween;
final T idleValue;
final ValueWidgetBuilder<T> builder;
final Curve curve;
Duration get totalDuration => duration + delay;
const GetAnimatedBuilder({
super.key,
this.curve = Curves.linear,
this.onComplete,
this.onStart,
required this.duration,
required this.tween,
required this.idleValue,
required this.builder,
required this.child,
required this.delay,
});
@override
GetAnimatedBuilderState<T> createState() => GetAnimatedBuilderState<T>();
}
class GetAnimatedBuilderState<T> extends State<GetAnimatedBuilder<T>>
with SingleTickerProviderStateMixin {
late final AnimationController _controller;
late final Animation<T> _animation;
// AnimationController get controller => _controller;
// Animation<T> get animation => _animation;
bool _wasStarted = false;
// bool get wasStarted => _wasStarted;
late T _idleValue;
bool _willResetOnDispose = false;
bool get willResetOnDispose => _willResetOnDispose;
void _listener(AnimationStatus status) {
switch (status) {
case AnimationStatus.completed:
widget.onComplete?.call(_controller);
if (_willResetOnDispose) {
_controller.reset();
}
break;
// case AnimationStatus.dismissed:
case AnimationStatus.forward:
widget.onStart?.call(_controller);
break;
// case AnimationStatus.reverse:
default:
break;
}
}
@override
void initState() {
super.initState();
if (widget is OpacityAnimation) {
final current =
context.findRootAncestorStateOfType<GetAnimatedBuilderState>();
final isLast = current == null;
if (widget is FadeInAnimation) {
_idleValue = 1.0 as dynamic;
} else {
if (isLast) {
_willResetOnDispose = false;
} else {
_willResetOnDispose = true;
}
_idleValue = widget.idleValue;
}
} else {
_idleValue = widget.idleValue;
}
_controller = AnimationController(
vsync: this,
duration: widget.duration,
);
_controller.addStatusListener(_listener);
_animation = widget.tween.animate(
CurvedAnimation(
parent: _controller,
curve: widget.curve,
),
);
Future.delayed(widget.delay, () {
if (mounted) {
setState(() {
_wasStarted = true;
_controller.forward();
});
}
});
}
@override
void dispose() {
_controller.removeStatusListener(_listener);
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _animation,
builder: (context, child) {
final value = _wasStarted ? _animation.value : _idleValue;
return widget.builder(context, value, child);
},
child: widget.child,
);
}
}
... ...
export './animations.dart';
export './extensions.dart';
export './get_animated_builder.dart';
... ...
... ... @@ -268,9 +268,9 @@ class GetConnect extends GetConnectInterface {
}) {
_checkIfDisposed(isHttp: false);
final _socket = GetSocket(_concatUrl(url)!, ping: ping);
sockets.add(_socket);
return _socket;
final newSocket = GetSocket(_concatUrl(url)!, ping: ping);
sockets.add(newSocket);
return newSocket;
}
String? _concatUrl(String? url) {
... ...
... ... @@ -16,7 +16,8 @@ typedef Decoder<T> = T Function(dynamic data);
typedef Progress = Function(double percent);
typedef ResponseInterceptor<T> = Future<Response<T>?> Function(Request<T> request, Type targetType, HttpClientResponse response);
typedef ResponseInterceptor<T> = Future<Response<T>?> Function(
Request<T> request, Type targetType, HttpClientResponse response);
class GetHttpClient {
String userAgent;
... ... @@ -38,7 +39,7 @@ class GetHttpClient {
bool errorSafety = true;
final HttpRequestBase _httpClient;
final IClient _httpClient;
final GetModifier _modifier;
... ... @@ -57,12 +58,14 @@ class GetHttpClient {
List<TrustedCertificate>? trustedCertificates,
bool withCredentials = false,
String Function(Uri url)? findProxy,
}) : _httpClient = createHttp(
allowAutoSignedCert: allowAutoSignedCert,
trustedCertificates: trustedCertificates,
withCredentials: withCredentials,
findProxy: findProxy,
),
IClient? customClient,
}) : _httpClient = customClient ??
createHttp(
allowAutoSignedCert: allowAutoSignedCert,
trustedCertificates: trustedCertificates,
withCredentials: withCredentials,
findProxy: findProxy,
),
_modifier = GetModifier();
void addAuthenticator<T>(RequestModifier<T> auth) {
... ... @@ -85,7 +88,7 @@ class GetHttpClient {
_modifier.removeResponseModifier<T>(interceptor);
}
Uri _createUri(String? url, Map<String, dynamic>? query) {
Uri createUri(String? url, Map<String, dynamic>? query) {
if (baseUrl != null) {
url = baseUrl! + url!;
}
... ... @@ -154,18 +157,17 @@ class GetHttpClient {
bodyStream = _trackProgress(bodyBytes, uploadProgress);
}
final uri = _createUri(url, query);
final uri = createUri(url, query);
return Request<T>(
method: method,
url: uri,
headers: headers,
bodyBytes: bodyStream,
contentLength: bodyBytes?.length ?? 0,
followRedirects: followRedirects,
maxRedirects: maxRedirects,
decoder: decoder,
responseInterceptor: responseInterceptor
);
method: method,
url: uri,
headers: headers,
bodyBytes: bodyStream,
contentLength: bodyBytes?.length ?? 0,
followRedirects: followRedirects,
maxRedirects: maxRedirects,
decoder: decoder,
responseInterceptor: responseInterceptor);
}
void _setContentLenght(Map<String, String> headers, int contentLength) {
... ... @@ -277,7 +279,7 @@ class GetHttpClient {
) {
final headers = <String, String>{};
_setSimpleHeaders(headers, contentType);
final uri = _createUri(url, query);
final uri = createUri(url, query);
return Future.value(Request<T>(
method: 'get',
... ... @@ -291,11 +293,14 @@ class GetHttpClient {
));
}
ResponseInterceptor<T>? _responseInterceptor<T>(ResponseInterceptor<T>? actual) {
if(actual != null) return actual;
ResponseInterceptor<T>? _responseInterceptor<T>(
ResponseInterceptor<T>? actual) {
if (actual != null) return actual;
final defaultInterceptor = defaultResponseInterceptor;
return defaultInterceptor != null
? (request, targetType, response) async => await defaultInterceptor(request, targetType, response) as Response<T>?
? (request, targetType, response) async =>
await defaultInterceptor(request, targetType, response)
as Response<T>?
: null;
}
... ... @@ -330,7 +335,7 @@ class GetHttpClient {
) {
final headers = <String, String>{};
_setSimpleHeaders(headers, contentType);
final uri = _createUri(url, query);
final uri = createUri(url, query);
return Request<T>(
method: 'delete',
... ... @@ -340,6 +345,7 @@ class GetHttpClient {
responseInterceptor: _responseInterceptor(responseInterceptor),
);
}
Future<Response<T>> send<T>(Request<T> request) async {
try {
var response = await _performRequest<T>(() => Future.value(request));
... ... @@ -521,78 +527,16 @@ class GetHttpClient {
}
}
// Future<Response<T>> download<T>(
// String url,
// String path, {
// Map<String, String> headers,
// String contentType = 'application/octet-stream',
// Map<String, dynamic> query,
// }) async {
// try {
// var response = await _performRequest<T>(
// () => _get<T>(url, contentType, query, null),
// headers: headers,
// );
// response.bodyBytes.listen((value) {});
// return response;
// } on Exception catch (e) {
// if (!errorSafety) {
// throw GetHttpException(e.toString());
// }
// return Future.value(Response<T>(
// statusText: 'Can not connect to server. Reason: $e',
// ));
// }
// int byteCount = 0;
// int totalBytes = httpResponse.contentLength;
// Directory appDocDir = await getApplicationDocumentsDirectory();
// String appDocPath = appDocDir.path;
// File file = File(path);
// var raf = file.openSync(mode: FileMode.write);
// Completer completer = Completer<String>();
// httpResponse.listen(
// (data) {
// byteCount += data.length;
// raf.writeFromSync(data);
// if (onDownloadProgress != null) {
// onDownloadProgress(byteCount, totalBytes);
// }
// },
// onDone: () {
// raf.closeSync();
// completer.complete(file.path);
// },
// onError: (e) {
// raf.closeSync();
// file.deleteSync();
// completer.completeError(e);
// },
// cancelOnError: true,
// );
// return completer.future;
// }
Future<Response<T>> delete<T>(
String url, {
Map<String, String>? headers,
String? contentType,
Map<String, dynamic>? query,
Decoder<T>? decoder,
ResponseInterceptor<T>? responseInterceptor
}) async {
Future<Response<T>> delete<T>(String url,
{Map<String, String>? headers,
String? contentType,
Map<String, dynamic>? query,
Decoder<T>? decoder,
ResponseInterceptor<T>? responseInterceptor}) async {
try {
var response = await _performRequest<T>(
() async => _delete<T>(url, contentType, query, decoder, responseInterceptor),
() async =>
_delete<T>(url, contentType, query, decoder, responseInterceptor),
headers: headers,
);
return response;
... ...
... ... @@ -4,7 +4,8 @@ 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 const FormatException(
'File is not "File" or "String" or "List<int>"');
}
}
... ...
... ... @@ -9,8 +9,8 @@ import '../../response/response.dart';
import '../interface/request_base.dart';
import '../utils/body_decoder.dart';
/// A `dart:html` implementation of `HttpRequestBase`.
class HttpRequestImpl implements HttpRequestBase {
/// A `dart:html` implementation of `IClient`.
class HttpRequestImpl implements IClient {
HttpRequestImpl({
bool allowAutoSignedCert = true,
List<TrustedCertificate>? trustedCertificates,
... ... @@ -51,7 +51,7 @@ class HttpRequestImpl implements HttpRequestBase {
var reader = FileReader();
reader.onLoad.first.then((_) async {
var bodyBytes = BodyBytesStream.fromBytes(reader.result as List<int>);
var bodyBytes = (reader.result as List<int>).toStream();
final stringBody =
await bodyBytesToString(bodyBytes, xhr.responseHeaders);
... ...
... ... @@ -2,7 +2,7 @@ import '../../request/request.dart';
import '../../response/response.dart';
/// Abstract interface of [HttpRequestImpl].
abstract class HttpRequestBase {
abstract class IClient {
/// Sends an HTTP [Request].
Future<Response<T>> send<T>(Request<T> request);
... ...
... ... @@ -12,7 +12,8 @@ List<int> fileToBytes(dynamic data) {
} else if (data is List<int>) {
return data;
} else {
throw FormatException('File is not "File" or "String" or "List<int>"');
throw const FormatException(
'File is not "File" or "String" or "List<int>"');
}
}
... ...
... ... @@ -8,9 +8,8 @@ import '../../response/response.dart';
import '../interface/request_base.dart';
import '../utils/body_decoder.dart';
/// A `dart:io` implementation of `HttpRequestBase`.
class HttpRequestImpl extends HttpRequestBase {
/// A `dart:io` implementation of `IClient`.
class HttpRequestImpl extends IClient {
io.HttpClient? _httpClient;
io.SecurityContext? _securityContext;
... ... @@ -58,10 +57,11 @@ class HttpRequestImpl extends HttpRequestBase {
});
final bodyBytes = (response);
final interceptionResponse = await request.responseInterceptor?.call(request, T, response);
if(interceptionResponse != null) return interceptionResponse;
final interceptionResponse =
await request.responseInterceptor?.call(request, T, response);
if (interceptionResponse != null) return interceptionResponse;
final stringBody = await bodyBytesToString(bodyBytes, headers);
final body = bodyDecoded<T>(
... ...
... ... @@ -5,7 +5,7 @@ import '../utils/body_decoder.dart';
typedef MockClientHandler = Future<Response> Function(Request request);
class MockClient extends HttpRequestBase {
class MockClient extends IClient {
/// The handler for than transforms request on response
final MockClientHandler _handler;
... ... @@ -16,7 +16,7 @@ class MockClient extends HttpRequestBase {
@override
Future<Response<T>> send<T>(Request<T> request) async {
var requestBody = await request.bodyBytes.toBytes();
var bodyBytes = BodyBytesStream.fromBytes(requestBody);
var bodyBytes = requestBody.toStream();
var response = await _handler(request);
... ...
... ... @@ -3,7 +3,7 @@ import '../../request/request.dart';
import '../../response/response.dart';
import '../interface/request_base.dart';
class HttpRequestImpl extends HttpRequestBase {
class HttpRequestImpl extends IClient {
HttpRequestImpl({
bool allowAutoSignedCert = true,
List<TrustedCertificate>? trustedCertificates,
... ...
... ... @@ -25,9 +25,9 @@ class FormData {
static const int _maxBoundaryLength = 70;
static String _getBoundary() {
final _random = Random();
final newRandom = Random();
var list = List<int>.generate(_maxBoundaryLength - GET_BOUNDARY.length,
(_) => boundaryCharacters[_random.nextInt(boundaryCharacters.length)],
(_) => boundaryCharacters[newRandom.nextInt(boundaryCharacters.length)],
growable: false);
return '$GET_BOUNDARY${String.fromCharCodes(list)}';
}
... ...
import '../http/stub/file_decoder_stub.dart'
if (dart.library.html) '../http/html/file_decoder_html.dart'
if (dart.library.io) '../http/io/file_decoder_io.dart';
import '../request/request.dart';
class MultipartFile {
... ... @@ -11,7 +10,7 @@ class MultipartFile {
this.contentType = 'application/octet-stream',
}) : _bytes = fileToBytes(data) {
_length = _bytes.length;
_stream = BodyBytesStream.fromBytes(_bytes);
_stream = _bytes.toStream();
}
final List<int> _bytes;
... ...
... ... @@ -68,7 +68,7 @@ class Request<T> {
return Request._(
url: url,
method: method,
bodyBytes: bodyBytes ??= BodyBytesStream.fromBytes(const []),
bodyBytes: bodyBytes ??= <int>[].toStream(),
headers: Map.from(headers),
followRedirects: followRedirects,
maxRedirects: maxRedirects,
... ... @@ -113,9 +113,11 @@ class Request<T> {
}
}
extension BodyBytesStream on Stream<List<int>> {
static Stream<List<int>> fromBytes(List<int> bytes) => Stream.value(bytes);
extension StreamExt on List<int> {
Stream<List<int>> toStream() => Stream.value(this).asBroadcastStream();
}
extension BodyBytesStream on Stream<List<int>> {
Future<Uint8List> toBytes() {
var completer = Completer<Uint8List>();
var sink = ByteConversionSink.withCallback(
... ...
import 'package:flutter/widgets.dart';
class Engine{
static WidgetsBinding get instance {
class Engine {
static WidgetsBinding get instance {
return WidgetsFlutterBinding.ensureInitialized();
}
}
\ No newline at end of file
}
... ...
... ... @@ -27,6 +27,24 @@ class InstanceInfo {
}
}
extension ResetInstance on GetInterface {
/// 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();
Inst._singl.clear();
return true;
}
}
extension Inst on GetInterface {
T call<T>() => find<T>();
... ... @@ -143,11 +161,11 @@ extension Inst on GetInterface {
_InstanceBuilderFactory<S>? dep;
if (_singl.containsKey(key)) {
final _dep = _singl[key];
if (_dep == null || !_dep.isDirty) {
final newDep = _singl[key];
if (newDep == null || !newDep.isDirty) {
return;
} else {
dep = _dep as _InstanceBuilderFactory<S>;
dep = newDep as _InstanceBuilderFactory<S>;
}
}
_singl[key] = _InstanceBuilderFactory<S>(
... ... @@ -311,22 +329,6 @@ extension Inst on GetInterface {
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
///
... ...
... ... @@ -5,7 +5,6 @@ export 'src/extension_navigation.dart';
export 'src/root/get_cupertino_app.dart';
export 'src/root/get_material_app.dart';
export 'src/root/internacionalization.dart';
export 'src/root/root_controller.dart';
export 'src/routes/custom_transition.dart';
export 'src/routes/default_route.dart';
export 'src/routes/get_route.dart';
... ...
... ... @@ -21,6 +21,7 @@ class GetModalBottomSheetRoute<T> extends PopupRoute<T> {
RouteSettings? settings,
this.enterBottomSheetDuration = const Duration(milliseconds: 250),
this.exitBottomSheetDuration = const Duration(milliseconds: 200),
this.curve,
}) : super(settings: settings) {
RouterReportManager.instance.reportCurrentRoute(this);
}
... ... @@ -38,11 +39,12 @@ class GetModalBottomSheetRoute<T> extends PopupRoute<T> {
// final String name;
final Duration enterBottomSheetDuration;
final Duration exitBottomSheetDuration;
final Curve? curve;
// remove safearea from top
final bool removeTop;
@override
Duration get transitionDuration => Duration(milliseconds: 700);
Duration get transitionDuration => const Duration(milliseconds: 700);
@override
bool get barrierDismissible => isDismissible;
... ... @@ -62,6 +64,14 @@ class GetModalBottomSheetRoute<T> extends PopupRoute<T> {
}
@override
Animation<double> createAnimation() {
if (curve != null) {
return CurvedAnimation(curve: curve!, parent: _animationController!.view);
}
return _animationController!.view;
}
@override
AnimationController createAnimationController() {
assert(_animationController == null);
_animationController =
... ...
... ... @@ -51,9 +51,9 @@ class GetDialogRoute<T> extends PopupRoute<T> {
Widget buildPage(BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation) {
return Semantics(
child: widget(context, animation, secondaryAnimation),
scopesRoute: true,
explicitChildNodes: true,
child: widget(context, animation, secondaryAnimation),
);
}
... ...
... ... @@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
import '../../get.dart';
import 'dialog/dialog_route.dart';
import 'root/get_root.dart';
/// It replaces the Flutter Navigator, but needs no context.
/// You can to use navigator.push(YourRoute()) rather
... ... @@ -27,6 +28,7 @@ extension ExtensionBottomSheet on GetInterface {
RouteSettings? settings,
Duration? enterBottomSheetDuration,
Duration? exitBottomSheetDuration,
Curve? curve,
}) {
return Navigator.of(overlayContext!, rootNavigator: useRootNavigator)
.push(GetModalBottomSheetRoute<T>(
... ... @@ -52,6 +54,7 @@ extension ExtensionBottomSheet on GetInterface {
enterBottomSheetDuration ?? const Duration(milliseconds: 250),
exitBottomSheetDuration:
exitBottomSheetDuration ?? const Duration(milliseconds: 200),
curve: curve,
));
}
}
... ... @@ -184,7 +187,7 @@ extension ExtensionDialog on GetInterface {
actions.add(TextButton(
style: TextButton.styleFrom(
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 8),
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 8),
shape: RoundedRectangleBorder(
side: BorderSide(
color: buttonColor ?? theme.colorScheme.secondary,
... ... @@ -217,8 +220,8 @@ extension ExtensionDialog on GetInterface {
),
child: Text(
textConfirm ?? "Ok",
style:
TextStyle(color: confirmTextColor ?? theme.backgroundColor),
style: TextStyle(
color: confirmTextColor ?? theme.colorScheme.background),
),
onPressed: () {
onConfirm?.call();
... ... @@ -227,8 +230,8 @@ extension ExtensionDialog on GetInterface {
}
Widget baseAlertDialog = AlertDialog(
titlePadding: titlePadding ?? EdgeInsets.all(8),
contentPadding: contentPadding ?? EdgeInsets.all(8),
titlePadding: titlePadding ?? const EdgeInsets.all(8),
contentPadding: contentPadding ?? const EdgeInsets.all(8),
backgroundColor: backgroundColor ?? theme.dialogBackgroundColor,
shape: RoundedRectangleBorder(
... ... @@ -241,7 +244,7 @@ extension ExtensionDialog on GetInterface {
content ??
Text(middleText,
textAlign: TextAlign.center, style: middleTextStyle),
SizedBox(height: 16),
const SizedBox(height: 16),
ButtonTheme(
minWidth: 78.0,
height: 34.0,
... ... @@ -392,6 +395,7 @@ extension ExtensionSnackbar on GetInterface {
Gradient? backgroundGradient,
TextButton? mainButton,
OnTap? onTap,
OnHover? onHover,
bool? isDismissible,
bool? showProgressIndicator,
DismissDirection? dismissDirection,
... ... @@ -430,14 +434,14 @@ extension ExtensionSnackbar on GetInterface {
),
snackPosition: snackPosition ?? SnackPosition.top,
borderRadius: borderRadius ?? 15,
margin: margin ?? EdgeInsets.symmetric(horizontal: 10),
margin: margin ?? const EdgeInsets.symmetric(horizontal: 10),
duration: duration,
barBlur: barBlur ?? 7.0,
backgroundColor: backgroundColor ?? Colors.grey.withOpacity(0.2),
icon: icon,
shouldIconPulse: shouldIconPulse ?? true,
maxWidth: maxWidth,
padding: padding ?? EdgeInsets.all(16),
padding: padding ?? const EdgeInsets.all(16),
borderColor: borderColor,
borderWidth: borderWidth,
leftBarIndicatorColor: leftBarIndicatorColor,
... ... @@ -445,6 +449,7 @@ extension ExtensionSnackbar on GetInterface {
backgroundGradient: backgroundGradient,
mainButton: mainButton,
onTap: onTap,
onHover: onHover,
isDismissible: isDismissible ?? true,
dismissDirection: dismissDirection,
showProgressIndicator: showProgressIndicator ?? false,
... ... @@ -454,7 +459,7 @@ extension ExtensionSnackbar on GetInterface {
snackStyle: snackStyle ?? SnackStyle.floating,
forwardAnimationCurve: forwardAnimationCurve ?? Curves.easeOutCirc,
reverseAnimationCurve: reverseAnimationCurve ?? Curves.easeOutCirc,
animationDuration: animationDuration ?? Duration(seconds: 1),
animationDuration: animationDuration ?? const Duration(seconds: 1),
overlayBlur: overlayBlur ?? 0.0,
overlayColor: overlayColor ?? Colors.transparent,
userInputForm: userInputForm);
... ... @@ -1007,36 +1012,36 @@ extension GetNavigationExt on GetInterface {
}
return Uri.tryParse(name)?.toString() ?? name;
}
/// change default config of Get
void config(
{bool? enableLog,
LogWriterCallback? logWriterCallback,
bool? defaultPopGesture,
bool? defaultOpaqueRoute,
Duration? defaultDurationTransition,
bool? defaultGlobalState,
Transition? defaultTransition}) {
if (enableLog != null) {
Get.isLogEnable = enableLog;
}
if (logWriterCallback != null) {
Get.log = logWriterCallback;
}
if (defaultPopGesture != null) {
_getxController.defaultPopGesture = defaultPopGesture;
}
if (defaultOpaqueRoute != null) {
_getxController.defaultOpaqueRoute = defaultOpaqueRoute;
}
if (defaultTransition != null) {
_getxController.defaultTransition = defaultTransition;
}
if (defaultDurationTransition != null) {
_getxController.defaultTransitionDuration = defaultDurationTransition;
}
}
//TODO: Deprecated
// /// change default config of Get
// void config(
// {bool? enableLog,
// LogWriterCallback? logWriterCallback,
// bool? defaultPopGesture,
// bool? defaultOpaqueRoute,
// Duration? defaultDurationTransition,
// bool? defaultGlobalState,
// Transition? defaultTransition}) {
// if (enableLog != null) {
// Get.isLogEnable = enableLog;
// }
// if (logWriterCallback != null) {
// Get.log = logWriterCallback;
// }
// if (defaultPopGesture != null) {
// _getxController.defaultPopGesture = defaultPopGesture;
// }
// if (defaultOpaqueRoute != null) {
// _getxController.defaultOpaqueRoute = defaultOpaqueRoute;
// }
// if (defaultTransition != null) {
// _getxController.defaultTransition = defaultTransition;
// }
// if (defaultDurationTransition != null) {
// _getxController.defaultTransitionDuration = defaultDurationTransition;
// }
// }
Future<void> updateLocale(Locale l) async {
Get.locale = l;
... ... @@ -1060,33 +1065,33 @@ extension GetNavigationExt on GetInterface {
await engine.performReassemble();
}
void appUpdate() => _getxController.update();
void appUpdate() => rootController.update();
void changeTheme(ThemeData theme) {
_getxController.setTheme(theme);
rootController.setTheme(theme);
}
void changeThemeMode(ThemeMode themeMode) {
_getxController.setThemeMode(themeMode);
rootController.setThemeMode(themeMode);
}
GlobalKey<NavigatorState>? addKey(GlobalKey<NavigatorState> newKey) {
return _getxController.addKey(newKey);
return rootController.addKey(newKey);
}
GetDelegate? nestedKey(String? key) {
return _getxController.nestedKey(key);
return rootController.nestedKey(key);
}
GetDelegate searchDelegate(dynamic k) {
GetDelegate _key;
GetDelegate key;
if (k == null) {
_key = Get.rootController.rootDelegate;
key = Get.rootController.rootDelegate;
} else {
if (!keys.containsKey(k)) {
throw 'Route id ($k) not found';
}
_key = keys[k]!;
key = keys[k]!;
}
// if (_key.listenersLength == 0 && !testMode) {
... ... @@ -1099,12 +1104,12 @@ extension GetNavigationExt on GetInterface {
// """;
// }
return _key;
return key;
}
/// give current arguments
//dynamic get arguments => routing.args;
dynamic get arguments => _getxController.rootDelegate.arguments();
dynamic get arguments => rootController.rootDelegate.arguments();
/// give name from current route
String get currentRoute => routing.current;
... ... @@ -1153,11 +1158,11 @@ extension GetNavigationExt on GetInterface {
/// give access to Theme.of(context)
ThemeData get theme {
var _theme = ThemeData.fallback();
var theme = ThemeData.fallback();
if (context != null) {
_theme = Theme.of(context!);
theme = Theme.of(context!);
}
return _theme;
return theme;
}
/// The current null safe [WidgetsBinding]
... ... @@ -1217,11 +1222,13 @@ extension GetNavigationExt on GetInterface {
// /// give access to Immutable MediaQuery.of(context).size.width
// double get width => MediaQuery.of(context).size.width;
GlobalKey<NavigatorState> get key => _getxController.key;
GlobalKey<NavigatorState> get key => rootController.key;
Map<dynamic, GetDelegate> get keys => _getxController.keys;
Map<dynamic, GetDelegate> get keys => rootController.keys;
GetMaterialController get rootController => _getxController;
GetRootState get rootController => GetRootState.controller;
ConfigData get _getxController => GetRootState.controller.config;
bool get defaultPopGesture => _getxController.defaultPopGesture;
bool get defaultOpaqueRoute => _getxController.defaultOpaqueRoute;
... ... @@ -1244,20 +1251,18 @@ extension GetNavigationExt on GetInterface {
Routing get routing => _getxController.routing;
Map<String, String?> get parameters =>
_getxController.rootDelegate.parameters;
set parameters(Map<String, String?> newParameters) =>
_getxController.parameters = newParameters;
rootController.parameters = newParameters;
set testMode(bool isTest) => rootController.testMode = isTest;
bool get testMode => _getxController.testMode;
set testMode(bool isTest) => _getxController.testMode = isTest;
Map<String, String?> get parameters => rootController.rootDelegate.parameters;
/// Casts the stored router delegate to a desired type
TDelegate? delegate<TDelegate extends RouterDelegate<TPage>, TPage>() =>
_getxController.routerDelegate as TDelegate?;
static final GetMaterialController _getxController =
Get.find<GetMaterialController>();
}
extension OverlayExt on GetInterface {
... ... @@ -1280,8 +1285,8 @@ extension OverlayExt on GetInterface {
});
final overlayEntryLoader = OverlayEntry(builder: (context) {
return loadingWidget ??
Center(
child: Container(
const Center(
child: SizedBox(
height: 90,
width: 90,
child: Text('Loading...'),
... ...
... ... @@ -7,11 +7,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';
import 'get_root.dart';
class GetCupertinoApp extends StatelessWidget {
final GlobalKey<NavigatorState>? navigatorKey;
final Widget? home;
final Map<String, WidgetBuilder>? routes;
final String? initialRoute;
... ... @@ -67,7 +66,7 @@ class GetCupertinoApp extends StatelessWidget {
final List<Bind> binds;
final ScrollBehavior? scrollBehavior;
GetCupertinoApp({
const GetCupertinoApp({
Key? key,
this.theme,
this.navigatorKey,
... ... @@ -128,18 +127,7 @@ class GetCupertinoApp extends StatelessWidget {
routerConfig = 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;
}
GetCupertinoApp.router({
const GetCupertinoApp.router({
Key? key,
this.theme,
this.routeInformationProvider,
... ... @@ -200,67 +188,53 @@ class GetCupertinoApp extends StatelessWidget {
@override
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: GlobalKey<ScaffoldMessengerState>(),
smartManagement: smartManagement,
transitionDuration: transitionDuration,
translations: translations,
translationsKeys: translationsKeys,
unknownRoute: unknownRoute,
),
),
onClose: () {
Get.clearTranslations();
RouterReportManager.dispose();
Get.resetInstance(clearRouteBindings: true);
},
),
...binds,
],
return GetRoot(
config: 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,
routeInformationParser: routeInformationParser,
routeInformationProvider: routeInformationProvider,
routerDelegate: routerDelegate,
routingCallback: routingCallback,
scaffoldMessengerKey: GlobalKey<ScaffoldMessengerState>(),
smartManagement: smartManagement,
transitionDuration: transitionDuration,
translations: translations,
translationsKeys: translationsKeys,
unknownRoute: unknownRoute,
),
child: Builder(builder: (context) {
final controller = context.listen<GetMaterialController>();
final controller = GetRoot.of(context);
return CupertinoApp.router(
routerDelegate: controller.routerDelegate,
routeInformationParser: controller.routeInformationParser,
routerDelegate: controller.config.routerDelegate,
routeInformationParser: controller.config.routeInformationParser,
backButtonDispatcher: backButtonDispatcher,
routeInformationProvider: routeInformationProvider,
routerConfig: routerConfig,
key: controller.unikey,
key: controller.config.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()),
? (child ?? const Material())
: builder!(context, child ?? const Material()),
),
title: title,
onGenerateTitle: onGenerateTitle,
... ...
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:get/instance_manager.dart';
import '../../../get_core/get_core.dart';
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';
import 'get_root.dart';
class GetMaterialApp extends StatelessWidget {
final GlobalKey<NavigatorState>? navigatorKey;
... ... @@ -132,7 +131,7 @@ class GetMaterialApp extends StatelessWidget {
routerConfig = null,
super(key: key);
GetMaterialApp.router({
const GetMaterialApp.router({
Key? key,
this.routeInformationProvider,
this.scaffoldMessengerKey,
... ... @@ -196,80 +195,80 @@ class GetMaterialApp extends StatelessWidget {
@override
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();
RouterReportManager.dispose();
Get.resetInstance(clearRouteBindings: true);
},
),
...binds,
],
return GetRoot(
config: 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,
routeInformationParser: routeInformationParser,
routeInformationProvider: routeInformationProvider,
routerDelegate: routerDelegate,
routingCallback: routingCallback,
scaffoldMessengerKey: scaffoldMessengerKey,
smartManagement: smartManagement,
transitionDuration: transitionDuration,
translations: translations,
translationsKeys: translationsKeys,
unknownRoute: unknownRoute,
theme: theme,
darkTheme: darkTheme,
themeMode: themeMode,
),
// binds: [
// Bind.lazyPut<GetMaterialController>(
// () => GetMaterialController(
// ),
// onClose: () {
// Get.clearTranslations();
// RouterReportManager.dispose();
// Get.resetInstance(clearRouteBindings: true);
// },
// ),
// ...binds,
// ],
child: Builder(builder: (context) {
final controller = context.listen<GetMaterialController>();
final controller = GetRoot.of(context);
return MaterialApp.router(
routerDelegate: controller.routerDelegate,
routeInformationParser: controller.routeInformationParser,
routerDelegate: controller.config.routerDelegate,
routeInformationParser: controller.config.routeInformationParser,
backButtonDispatcher: backButtonDispatcher,
routeInformationProvider: routeInformationProvider,
routerConfig: routerConfig,
key: controller.unikey,
key: controller.config.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()),
? (child ?? const Material())
: builder!(context, child ?? const Material()),
),
title: title,
onGenerateTitle: onGenerateTitle,
color: color,
theme: controller.theme ?? theme ?? ThemeData.fallback(),
darkTheme: controller.darkTheme ??
darkTheme ??
theme ??
theme: controller.config.theme ?? ThemeData.fallback(),
darkTheme: controller.config.darkTheme ??
controller.config.theme ??
ThemeData.fallback(),
themeMode: controller.themeMode ?? themeMode,
themeMode: controller.config.themeMode,
locale: Get.locale ?? locale,
scaffoldMessengerKey:
scaffoldMessengerKey ?? controller.scaffoldMessengerKey,
scaffoldMessengerKey: controller.config.scaffoldMessengerKey,
localizationsDelegates: localizationsDelegates,
localeListResolutionCallback: localeListResolutionCallback,
localeResolutionCallback: localeResolutionCallback,
... ...
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import '../../../get.dart';
import '../router_report.dart';
class ConfigData {
final ValueChanged<Routing?>? routingCallback;
final Transition? defaultTransition;
final VoidCallback? onInit;
final VoidCallback? onReady;
final VoidCallback? onDispose;
final bool? enableLog;
final LogWriterCallback? logWriterCallback;
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;
final bool testMode;
final Key? unikey;
final ThemeData? theme;
final ThemeData? darkTheme;
final ThemeMode? themeMode;
final bool defaultPopGesture;
final bool defaultOpaqueRoute;
final Duration defaultTransitionDuration;
final Curve defaultTransitionCurve;
final Curve defaultDialogTransitionCurve;
final Duration defaultDialogTransitionDuration;
final Routing routing;
final Map<String, String?> parameters;
ConfigData({
required this.routingCallback,
required this.defaultTransition,
required this.onInit,
required this.onReady,
required this.onDispose,
required this.enableLog,
required this.logWriterCallback,
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,
this.theme,
this.darkTheme,
this.themeMode,
this.unikey,
this.testMode = false,
this.defaultOpaqueRoute = true,
this.defaultTransitionDuration = const Duration(milliseconds: 300),
this.defaultTransitionCurve = Curves.easeOutQuad,
this.defaultDialogTransitionCurve = Curves.easeOutQuad,
this.defaultDialogTransitionDuration = const Duration(milliseconds: 300),
this.parameters = const {},
Routing? routing,
bool? defaultPopGesture,
}) : defaultPopGesture = defaultPopGesture ?? GetPlatform.isIOS,
routing = routing ?? Routing();
ConfigData copyWith({
ValueChanged<Routing?>? routingCallback,
Transition? defaultTransition,
VoidCallback? onInit,
VoidCallback? onReady,
VoidCallback? onDispose,
bool? enableLog,
LogWriterCallback? logWriterCallback,
SmartManagement? smartManagement,
List<Bind>? binds,
Duration? transitionDuration,
bool? defaultGlobalState,
List<GetPage>? getPages,
GetPage? unknownRoute,
RouteInformationProvider? routeInformationProvider,
RouteInformationParser<Object>? routeInformationParser,
RouterDelegate<Object>? routerDelegate,
BackButtonDispatcher? backButtonDispatcher,
List<NavigatorObserver>? navigatorObservers,
GlobalKey<NavigatorState>? navigatorKey,
GlobalKey<ScaffoldMessengerState>? scaffoldMessengerKey,
Map<String, Map<String, String>>? translationsKeys,
Translations? translations,
Locale? locale,
Locale? fallbackLocale,
String? initialRoute,
CustomTransition? customTransition,
Widget? home,
bool? testMode,
Key? unikey,
ThemeData? theme,
ThemeData? darkTheme,
ThemeMode? themeMode,
bool? defaultPopGesture,
bool? defaultOpaqueRoute,
Duration? defaultTransitionDuration,
Curve? defaultTransitionCurve,
Curve? defaultDialogTransitionCurve,
Duration? defaultDialogTransitionDuration,
Routing? routing,
Map<String, String?>? parameters,
}) {
return ConfigData(
routingCallback: routingCallback ?? this.routingCallback,
defaultTransition: defaultTransition ?? this.defaultTransition,
onInit: onInit ?? this.onInit,
onReady: onReady ?? this.onReady,
onDispose: onDispose ?? this.onDispose,
enableLog: enableLog ?? this.enableLog,
logWriterCallback: logWriterCallback ?? this.logWriterCallback,
smartManagement: smartManagement ?? this.smartManagement,
binds: binds ?? this.binds,
transitionDuration: transitionDuration ?? this.transitionDuration,
defaultGlobalState: defaultGlobalState ?? this.defaultGlobalState,
getPages: getPages ?? this.getPages,
unknownRoute: unknownRoute ?? this.unknownRoute,
routeInformationProvider:
routeInformationProvider ?? this.routeInformationProvider,
routeInformationParser:
routeInformationParser ?? this.routeInformationParser,
routerDelegate: routerDelegate ?? this.routerDelegate,
backButtonDispatcher: backButtonDispatcher ?? this.backButtonDispatcher,
navigatorObservers: navigatorObservers ?? this.navigatorObservers,
navigatorKey: navigatorKey ?? this.navigatorKey,
scaffoldMessengerKey: scaffoldMessengerKey ?? this.scaffoldMessengerKey,
translationsKeys: translationsKeys ?? this.translationsKeys,
translations: translations ?? this.translations,
locale: locale ?? this.locale,
fallbackLocale: fallbackLocale ?? this.fallbackLocale,
initialRoute: initialRoute ?? this.initialRoute,
customTransition: customTransition ?? this.customTransition,
home: home ?? this.home,
testMode: testMode ?? this.testMode,
unikey: unikey ?? this.unikey,
theme: theme ?? this.theme,
darkTheme: darkTheme ?? this.darkTheme,
themeMode: themeMode ?? this.themeMode,
defaultPopGesture: defaultPopGesture ?? this.defaultPopGesture,
defaultOpaqueRoute: defaultOpaqueRoute ?? this.defaultOpaqueRoute,
defaultTransitionDuration:
defaultTransitionDuration ?? this.defaultTransitionDuration,
defaultTransitionCurve:
defaultTransitionCurve ?? this.defaultTransitionCurve,
defaultDialogTransitionCurve:
defaultDialogTransitionCurve ?? this.defaultDialogTransitionCurve,
defaultDialogTransitionDuration: defaultDialogTransitionDuration ??
this.defaultDialogTransitionDuration,
routing: routing ?? this.routing,
parameters: parameters ?? this.parameters,
);
}
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is ConfigData &&
other.routingCallback == routingCallback &&
other.defaultTransition == defaultTransition &&
other.onInit == onInit &&
other.onReady == onReady &&
other.onDispose == onDispose &&
other.enableLog == enableLog &&
other.logWriterCallback == logWriterCallback &&
other.smartManagement == smartManagement &&
listEquals(other.binds, binds) &&
other.transitionDuration == transitionDuration &&
other.defaultGlobalState == defaultGlobalState &&
listEquals(other.getPages, getPages) &&
other.unknownRoute == unknownRoute &&
other.routeInformationProvider == routeInformationProvider &&
other.routeInformationParser == routeInformationParser &&
other.routerDelegate == routerDelegate &&
other.backButtonDispatcher == backButtonDispatcher &&
listEquals(other.navigatorObservers, navigatorObservers) &&
other.navigatorKey == navigatorKey &&
other.scaffoldMessengerKey == scaffoldMessengerKey &&
mapEquals(other.translationsKeys, translationsKeys) &&
other.translations == translations &&
other.locale == locale &&
other.fallbackLocale == fallbackLocale &&
other.initialRoute == initialRoute &&
other.customTransition == customTransition &&
other.home == home &&
other.testMode == testMode &&
other.unikey == unikey &&
other.theme == theme &&
other.darkTheme == darkTheme &&
other.themeMode == themeMode &&
other.defaultPopGesture == defaultPopGesture &&
other.defaultOpaqueRoute == defaultOpaqueRoute &&
other.defaultTransitionDuration == defaultTransitionDuration &&
other.defaultTransitionCurve == defaultTransitionCurve &&
other.defaultDialogTransitionCurve == defaultDialogTransitionCurve &&
other.defaultDialogTransitionDuration ==
defaultDialogTransitionDuration &&
other.routing == routing &&
mapEquals(other.parameters, parameters);
}
@override
int get hashCode {
return routingCallback.hashCode ^
defaultTransition.hashCode ^
onInit.hashCode ^
onReady.hashCode ^
onDispose.hashCode ^
enableLog.hashCode ^
logWriterCallback.hashCode ^
smartManagement.hashCode ^
binds.hashCode ^
transitionDuration.hashCode ^
defaultGlobalState.hashCode ^
getPages.hashCode ^
unknownRoute.hashCode ^
routeInformationProvider.hashCode ^
routeInformationParser.hashCode ^
routerDelegate.hashCode ^
backButtonDispatcher.hashCode ^
navigatorObservers.hashCode ^
navigatorKey.hashCode ^
scaffoldMessengerKey.hashCode ^
translationsKeys.hashCode ^
translations.hashCode ^
locale.hashCode ^
fallbackLocale.hashCode ^
initialRoute.hashCode ^
customTransition.hashCode ^
home.hashCode ^
testMode.hashCode ^
unikey.hashCode ^
theme.hashCode ^
darkTheme.hashCode ^
themeMode.hashCode ^
defaultPopGesture.hashCode ^
defaultOpaqueRoute.hashCode ^
defaultTransitionDuration.hashCode ^
defaultTransitionCurve.hashCode ^
defaultDialogTransitionCurve.hashCode ^
defaultDialogTransitionDuration.hashCode ^
routing.hashCode ^
parameters.hashCode;
}
}
class GetRoot extends StatefulWidget {
const GetRoot({
Key? key,
required this.config,
required this.child,
}) : super(key: key);
final ConfigData config;
final Widget child;
@override
State<GetRoot> createState() => GetRootState();
static GetRootState of(BuildContext context) {
// Handles the case where the input context is a navigator element.
GetRootState? root;
if (context is StatefulElement && context.state is GetRootState) {
root = context.state as GetRootState;
}
root = context.findRootAncestorStateOfType<GetRootState>() ?? root;
assert(() {
if (root == null) {
throw FlutterError(
'GetRoot operation requested with a context that does not include a GetRoot.\n'
'The context used must be that of a '
'widget that is a descendant of a GetRoot widget.',
);
}
return true;
}());
return root!;
}
}
class GetRootState extends State<GetRoot> with WidgetsBindingObserver {
static GetRootState? _controller;
static GetRootState get controller {
if (_controller == null) {
throw Exception('GetRoot is not part of the three');
} else {
return _controller!;
}
}
late ConfigData config;
@override
void initState() {
config = widget.config;
GetRootState._controller = this;
ambiguate(Engine.instance)!.addObserver(this);
onInit();
super.initState();
}
// @override
// void didUpdateWidget(covariant GetRoot oldWidget) {
// if (oldWidget.config != widget.config) {
// config = widget.config;
// }
// super.didUpdateWidget(oldWidget);
// }
void onClose() {
config.onDispose?.call();
Get.clearTranslations();
RouterReportManager.instance.clearRouteKeys();
RouterReportManager.dispose();
Get.resetInstance(clearRouteBindings: true);
_controller = null;
ambiguate(Engine.instance)!.removeObserver(this);
}
@override
void dispose() {
onClose();
super.dispose();
}
void onInit() {
if (config.getPages == null && config.home == null) {
throw 'You need add pages or home';
}
if (config.routerDelegate == null) {
final newDelegate = GetDelegate.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, config.routing),
...config.navigatorObservers!
]),
);
config = config.copyWith(routerDelegate: newDelegate);
}
if (config.routeInformationParser == null) {
final newRouteInformationParser =
GetInformationParser.createInformationParser(
initialRoute: config.initialRoute ??
config.getPages?.first.name ??
cleanRouteName("/${config.home.runtimeType}"),
);
config =
config.copyWith(routeInformationParser: newRouteInformationParser);
}
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!);
}
Get.smartManagement = config.smartManagement;
config.onInit?.call();
Get.isLogEnable = config.enableLog ?? kDebugMode;
Get.log = config.logWriterCallback ?? defaultLogWriterCallback;
if (config.defaultTransition == null) {
config = config.copyWith(defaultTransition: getThemeTransition());
}
// defaultOpaqueRoute = config.opaqueRoute ?? true;
// defaultPopGesture = config.popGesture ?? GetPlatform.isIOS;
// defaultTransitionDuration =
// config.transitionDuration ?? Duration(milliseconds: 300);
Future(() => onReady());
}
set parameters(Map<String, String?> newParameters) {
// rootController.parameters = newParameters;
config = config.copyWith(parameters: newParameters);
}
set testMode(bool isTest) {
config = config.copyWith(testMode: isTest);
// _getxController.testMode = isTest;
}
void onReady() {
config.onReady?.call();
}
Transition? getThemeTransition() {
final platform = Get.theme.platform;
final matchingTransition =
Get.theme.pageTransitionsTheme.builders[platform];
switch (matchingTransition) {
case CupertinoPageTransitionsBuilder():
return Transition.cupertino;
case ZoomPageTransitionsBuilder():
return Transition.zoom;
case FadeUpwardsPageTransitionsBuilder():
return Transition.fade;
case OpenUpwardsPageTransitionsBuilder():
return Transition.native;
default:
return null;
}
}
@override
void didChangeLocales(List<Locale>? locales) {
Get.asap(() {
final locale = Get.deviceLocale;
if (locale != null) {
Get.updateLocale(locale);
}
});
}
void setTheme(ThemeData value) {
if (config.darkTheme == null) {
config = config.copyWith(theme: value);
} else {
if (value.brightness == Brightness.light) {
config = config.copyWith(theme: value);
} else {
config = config.copyWith(darkTheme: value);
}
}
update();
}
void setThemeMode(ThemeMode value) {
config = config.copyWith(themeMode: value);
update();
}
void restartApp() {
config = config.copyWith(unikey: UniqueKey());
update();
}
void update() {
setState(() {});
}
GlobalKey<NavigatorState> get key => rootDelegate.navigatorKey;
GetDelegate get rootDelegate => config.routerDelegate as GetDelegate;
RouteInformationParser<Object> get informationParser =>
config.routeInformationParser!;
GlobalKey<NavigatorState>? addKey(GlobalKey<NavigatorState> newKey) {
rootDelegate.navigatorKey = newKey;
return key;
}
Map<dynamic, GetDelegate> keys = {};
GetDelegate? nestedKey(String? key) {
if (key == null) {
return rootDelegate;
}
keys.putIfAbsent(
key,
() => GetDelegate(
showHashOnUrl: true,
//debugLabel: 'Getx nested key: ${key.toString()}',
pages: RouteDecoder.fromRoute(key).currentChildrens ?? [],
),
);
return keys[key];
}
@override
Widget build(BuildContext context) {
return widget.child;
}
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;
}
}
... ...
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 {
GetMaterialController(this.config);
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';
}
print('route delefate from onInit');
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.smartManagement = config.smartManagement;
config.onInit?.call();
Get.isLogEnable = config.enableLog ?? kDebugMode;
Get.log = config.logWriterCallback ?? defaultLogWriterCallback;
defaultTransition = config.defaultTransition ?? getThemeTransition();
defaultOpaqueRoute = config.opaqueRoute ?? true;
defaultPopGesture = config.popGesture ?? GetPlatform.isIOS;
defaultTransitionDuration =
config.transitionDuration ?? Duration(milliseconds: 300);
}
Transition? getThemeTransition() {
final platform = Get.theme.platform;
final matchingTransition =
Get.theme.pageTransitionsTheme.builders[platform];
switch (matchingTransition) {
case CupertinoPageTransitionsBuilder():
return Transition.cupertino;
case ZoomPageTransitionsBuilder():
return Transition.zoom;
case FadeUpwardsPageTransitionsBuilder():
return Transition.fade;
case OpenUpwardsPageTransitionsBuilder():
return Transition.native;
default:
return null;
}
}
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;
ThemeData? theme;
ThemeData? darkTheme;
ThemeMode? themeMode;
final scaffoldMessengerKey = GlobalKey<ScaffoldMessengerState>();
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 => routerDelegate as GetDelegate;
GlobalKey<NavigatorState>? addKey(GlobalKey<NavigatorState> newKey) {
rootDelegate.navigatorKey = newKey;
return key;
}
@override
void didChangeLocales(List<Locale>? locales) {
Get.asap(() {
final locale = Get.deviceLocale;
if (locale != null) {
Get.updateLocale(locale);
}
});
}
void restartApp() {
unikey = UniqueKey();
update();
}
void setTheme(ThemeData value) {
if (darkTheme == null) {
theme = value;
} else {
if (value.brightness == Brightness.light) {
theme = value;
} else {
darkTheme = value;
}
}
update();
}
void setThemeMode(ThemeMode value) {
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,
);
}
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,
);
}
}
import 'dart:collection';
import 'package:flutter/widgets.dart';
import '../../get.dart';
class RouterReportManager<T> {
... ...
... ... @@ -132,15 +132,15 @@ class GetPageRoute<T> extends PageRoute<T>
final dep = item.dependencies();
if (dep is List<Bind>) {
_child = Binds(
child: middlewareRunner.runOnPageBuilt(pageToBuild()),
binds: dep,
child: middlewareRunner.runOnPageBuilt(pageToBuild()),
);
}
}
} else if (bindingsToBind is List<Bind>) {
_child = Binds(
child: middlewareRunner.runOnPageBuilt(pageToBuild()),
binds: bindingsToBind,
child: middlewareRunner.runOnPageBuilt(pageToBuild()),
);
}
}
... ...
... ... @@ -89,7 +89,7 @@ class SlideDownTransition {
Widget child) {
return SlideTransition(
position: Tween<Offset>(
begin: Offset(0.0, 1.0),
begin: const Offset(0.0, 1.0),
end: Offset.zero,
).animate(animation),
child: child,
... ... @@ -107,7 +107,7 @@ class SlideLeftTransition {
Widget child) {
return SlideTransition(
position: Tween<Offset>(
begin: Offset(-1.0, 0.0),
begin: const Offset(-1.0, 0.0),
end: Offset.zero,
).animate(animation),
child: child,
... ... @@ -125,7 +125,7 @@ class SlideRightTransition {
Widget child) {
return SlideTransition(
position: Tween<Offset>(
begin: Offset(1.0, 0.0),
begin: const Offset(1.0, 0.0),
end: Offset.zero,
).animate(animation),
child: child,
... ... @@ -143,7 +143,7 @@ class SlideTopTransition {
Widget child) {
return SlideTransition(
position: Tween<Offset>(
begin: Offset(0.0, -1.0),
begin: const Offset(0.0, -1.0),
end: Offset.zero,
).animate(animation),
child: child,
... ...
... ... @@ -4,6 +4,11 @@ import 'package:flutter/widgets.dart';
import '../../../get.dart';
class GetInformationParser extends RouteInformationParser<RouteDecoder> {
factory GetInformationParser.createInformationParser(
{String initialRoute = '/'}) {
return GetInformationParser(initialRoute: initialRoute);
}
final String initialRoute;
GetInformationParser({
... ... @@ -19,7 +24,7 @@ class GetInformationParser extends RouteInformationParser<RouteDecoder> {
if (location == '/') {
//check if there is a corresponding page
//if not, relocate to initialRoute
if (!(Get.rootController.routerDelegate as GetDelegate)
if (!(Get.rootController.rootDelegate)
.registeredRoutes
.any((element) => element.name == '/')) {
location = initialRoute;
... ...
... ... @@ -48,7 +48,7 @@ class GetNavigator extends Navigator {
);
GetNavigator({
GlobalKey<NavigatorState>? key,
Key? key,
bool Function(Route<dynamic>, dynamic)? onPopPage,
required List<GetPage> pages,
List<NavigatorObserver>? observers,
... ...
... ... @@ -43,8 +43,10 @@ class GetPage<T> extends Page<T> {
@override
final String name;
final bool inheritParentPath;
final List<GetPage> children;
final List<GetMiddleware>? middlewares;
final List<GetMiddleware> middlewares;
final PathDecoded path;
final GetPage? unknownRoute;
final bool showCupertinoParallax;
... ... @@ -73,7 +75,7 @@ class GetPage<T> extends Page<T> {
this.customTransition,
this.fullscreenDialog = false,
this.children = const <GetPage>[],
this.middlewares,
this.middlewares = const [],
this.unknownRoute,
this.arguments,
this.showCupertinoParallax = true,
... ... @@ -81,6 +83,7 @@ class GetPage<T> extends Page<T> {
this.preventDuplicateHandlingMode =
PreventDuplicateHandlingMode.reorderRoutes,
this.completer,
this.inheritParentPath = true,
LocalKey? key,
}) : path = _nameToRegex(name),
assert(name.startsWith('/'),
... ... @@ -92,7 +95,7 @@ class GetPage<T> extends Page<T> {
);
// settings = RouteSettings(name: name, arguments: Get.arguments);
GetPage<T> copy({
GetPage<T> copyWith({
LocalKey? key,
String? name,
GetPageBuilder? page,
... ... @@ -121,6 +124,7 @@ class GetPage<T> extends Page<T> {
Object? arguments,
bool? showCupertinoParallax,
Completer<T?>? completer,
bool? inheritParentPath,
}) {
return GetPage(
key: key ?? this.key,
... ... @@ -153,25 +157,26 @@ class GetPage<T> extends Page<T> {
showCupertinoParallax:
showCupertinoParallax ?? this.showCupertinoParallax,
completer: completer ?? this.completer,
inheritParentPath: inheritParentPath ?? this.inheritParentPath,
);
}
@override
Route<T> createRoute(BuildContext context) {
// return GetPageRoute<T>(settings: this, page: page);
final _page = PageRedirect(
final page = PageRedirect(
route: this,
settings: this,
unknownRoute: unknownRoute,
).getPageToRoute<T>(this, unknownRoute, context);
return _page;
return page;
}
static PathDecoded _nameToRegex(String path) {
var keys = <String?>[];
String _replace(Match pattern) {
String recursiveReplace(Match pattern) {
var buffer = StringBuffer('(?:');
if (pattern[1] != null) buffer.write('.');
... ... @@ -183,7 +188,7 @@ class GetPage<T> extends Page<T> {
}
var stringPath = '$path/?'
.replaceAllMapped(RegExp(r'(\.)?:(\w+)(\?)?'), _replace)
.replaceAllMapped(RegExp(r'(\.)?:(\w+)(\?)?'), recursiveReplace)
.replaceAll('//', '/');
return PathDecoded(RegExp('^$stringPath\$'), keys);
... ...
... ... @@ -12,6 +12,27 @@ class GetDelegate extends RouterDelegate<RouteDecoder>
ChangeNotifier,
PopNavigatorRouterDelegateMixin<RouteDecoder>,
IGetNavigation {
factory 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,
);
}
final List<RouteDecoder> _activePages = <RouteDecoder>[];
final PopMode backButtonPopMode;
final PreventDuplicateHandlingMode preventDuplicateHandlingMode;
... ... @@ -72,7 +93,7 @@ class GetDelegate extends RouterDelegate<RouteDecoder>
}) : navigatorKey = navigatorKey ?? GlobalKey<NavigatorState>(),
notFoundRoute = notFoundRoute ??= GetPage(
name: '/404',
page: () => Scaffold(
page: () => const Scaffold(
body: Center(child: Text('Route not found')),
),
) {
... ... @@ -84,7 +105,7 @@ class GetDelegate extends RouterDelegate<RouteDecoder>
Future<RouteDecoder?> runMiddleware(RouteDecoder config) async {
final middlewares = config.currentTreeBranch.last.middlewares;
if (middlewares == null) {
if (middlewares.isEmpty) {
return config;
}
var iterator = config;
... ... @@ -112,11 +133,11 @@ class GetDelegate extends RouterDelegate<RouteDecoder>
_activePages.add(res);
}
Future<T?> _unsafeHistoryRemove<T>(RouteDecoder config, T result) async {
var index = _activePages.indexOf(config);
if (index >= 0) return _unsafeHistoryRemoveAt(index, result);
return null;
}
// Future<T?> _unsafeHistoryRemove<T>(RouteDecoder config, T result) async {
// var index = _activePages.indexOf(config);
// if (index >= 0) return _unsafeHistoryRemoveAt(index, result);
// return null;
// }
Future<T?> _unsafeHistoryRemoveAt<T>(int index, T result) async {
if (index == _activePages.length - 1 && _activePages.length > 1) {
... ... @@ -145,10 +166,6 @@ class GetDelegate extends RouterDelegate<RouteDecoder>
return currentConfiguration?.pageSettings;
}
Future<T?> _removeHistoryEntry<T>(RouteDecoder entry, T result) async {
return _unsafeHistoryRemove<T>(entry, result);
}
Future<void> _pushHistory(RouteDecoder config) async {
if (config.route!.preventDuplicates) {
final originalEntryIndex = _activePages.indexWhere(
... ... @@ -560,7 +577,6 @@ class GetDelegate extends RouterDelegate<RouteDecoder>
_activePages.remove(RouteDecoder.fromRoute(name));
}
bool get canBack {
return _activePages.length > 1;
}
... ... @@ -691,7 +707,7 @@ class GetDelegate extends RouterDelegate<RouteDecoder>
decoder.parameters.addAll(parameters);
}
decoder.route = decoder.route?.copy(
decoder.route = decoder.route?.copyWith(
completer: _activePages.isEmpty ? null : Completer(),
arguments: arguments,
parameters: parameters,
... ... @@ -786,7 +802,7 @@ class GetDelegate extends RouterDelegate<RouteDecoder>
if (wasPopup) return true;
if (_canPop(popMode ?? backButtonPopMode)) {
await _pop(popMode ?? backButtonPopMode, result);
await _pop(popMode ?? backButtonPopMode, result);
notifyListeners();
return true;
}
... ... @@ -801,7 +817,6 @@ class GetDelegate extends RouterDelegate<RouteDecoder>
notifyListeners();
}
bool _onPopVisualRoute(Route<dynamic> route, dynamic result) {
final didPop = route.didPop(result);
if (!didPop) {
... ...
... ... @@ -7,6 +7,7 @@ import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import '../../../get.dart';
import '../root/get_root.dart';
const double _kBackGestureWidth = 20.0;
... ... @@ -379,8 +380,8 @@ Cannot read the previousTitle for a route that has not yet been installed''',
? CurvedAnimation(parent: animation, curve: finalCurve)
: animation,
secondaryRouteAnimation: secondaryAnimation,
child: child,
linearTransition: linearTransition,
child: child,
);
} else {
if (route.customTransition != null) {
... ... @@ -635,7 +636,7 @@ Cannot read the previousTitle for a route that has not yet been installed''',
));
case Transition.fade:
return FadeUpwardsPageTransitionsBuilder().buildTransitions(
return const FadeUpwardsPageTransitionsBuilder().buildTransitions(
route,
context,
animation,
... ... @@ -655,7 +656,7 @@ Cannot read the previousTitle for a route that has not yet been installed''',
));
case Transition.topLevel:
return ZoomPageTransitionsBuilder().buildTransitions(
return const ZoomPageTransitionsBuilder().buildTransitions(
route,
context,
animation,
... ... @@ -675,7 +676,7 @@ Cannot read the previousTitle for a route that has not yet been installed''',
));
case Transition.native:
return PageTransitionsTheme().buildTransitions(
return const PageTransitionsTheme().buildTransitions(
route,
context,
iosAnimation,
... ... @@ -716,8 +717,8 @@ Cannot read the previousTitle for a route that has not yet been installed''',
));
default:
final customTransition =
context.get<GetMaterialController>().customTransition;
final customTransition = GetRoot.of(context).config.customTransition;
if (customTransition != null) {
return customTransition.buildTransition(context, route.curve,
route.alignment, animation, secondaryAnimation, child);
... ...
... ... @@ -57,17 +57,17 @@ class Dependencies {
}
abstract class Module extends StatefulWidget {
Module({Key? key}) : super(key: key);
const Module({Key? key}) : super(key: key);
Widget view(BuildContext context);
void dependencies(Dependencies i);
@override
_ModuleState createState() => _ModuleState();
ModuleState createState() => ModuleState();
}
class _ModuleState extends State<Module> {
class ModuleState extends State<Module> {
@override
void initState() {
RouterReportManager.instance.reportCurrentRoute(this);
... ...
import 'dart:async';
import 'package:flutter/widgets.dart';
import 'get_route.dart';
class RouteMatcher {
final RouteNode _root = RouteNode('/', '/');
RouteNode addRoute(String path) {
final segments = _parsePath(path);
var currentNode = _root;
for (final segment in segments) {
final existingChild = currentNode.findChild(segment);
if (existingChild != null) {
currentNode = existingChild;
} else {
final newChild = RouteNode(segment, path);
currentNode.addChild(newChild);
currentNode = newChild;
}
}
return currentNode;
}
void removeRoute(String path) {
final segments = _parsePath(path);
var currentNode = _root;
RouteNode? nodeToDelete;
// Traverse the tree to find the node to delete
for (final segment in segments) {
final child = currentNode.findChild(segment);
if (child == null) {
return; // Node not found, nothing to delete
}
if (child.nodeSegments.length == segments.length) {
nodeToDelete = child;
break;
}
currentNode = child;
}
if (nodeToDelete == null) {
return; // Node not found, nothing to delete
}
final parent = nodeToDelete.parent!;
parent.nodeSegments.remove(nodeToDelete);
}
RouteNode? _findChild(RouteNode currentNode, String segment) {
return currentNode.nodeSegments
.firstWhereOrNull((node) => node.matches(segment));
}
MatchResult? matchRoute(String path) {
final uri = Uri.parse(path);
final segments = _parsePath(uri.path);
var currentNode = _root;
final parameters = <String, String>{};
final urlParameters = uri.queryParameters;
for (final segment in segments) {
if (segment.isEmpty) continue;
final child = _findChild(currentNode, segment);
if (child == null) {
return null;
} else {
if (child.path.startsWith(':')) {
parameters[child.path.substring(1)] = segment;
}
if (child.nodeSegments.length == segments.length) {
return null;
}
currentNode = child;
}
}
return MatchResult(
currentNode,
parameters,
path,
urlParameters: urlParameters,
);
}
List<String> _parsePath(String path) {
return path.split('/').where((segment) => segment.isNotEmpty).toList();
}
}
class RouteTreeResult {
final GetPage? route;
final MatchResult matchResult;
RouteTreeResult({
required this.route,
required this.matchResult,
});
@override
String toString() {
return 'RouteTreeResult(route: $route, matchResult: $matchResult)';
}
RouteTreeResult configure(String page, Object? arguments) {
return copyWith(
route: route?.copyWith(
key: ValueKey(page),
settings: RouteSettings(name: page, arguments: arguments),
completer: Completer(),
arguments: arguments,
));
}
RouteTreeResult copyWith({
GetPage? route,
MatchResult? matchResult,
}) {
return RouteTreeResult(
route: route ?? this.route,
matchResult: matchResult ?? this.matchResult,
);
}
}
class RouteTree {
static final instance = RouteTree();
final Map<String, GetPage> tree = {};
final RouteMatcher matcher = RouteMatcher();
void addRoute(GetPage route) {
matcher.addRoute(route.name);
tree[route.name] = route;
handleChild(route);
}
void addRoutes(List<GetPage> routes) {
for (var route in routes) {
addRoute(route);
}
}
void handleChild(GetPage route) {
final children = route.children;
for (var child in children) {
final middlewares = List.of(route.middlewares);
final bindings = List.of(route.bindings);
middlewares.addAll(child.middlewares);
bindings.addAll(child.bindings);
child = child.copyWith(middlewares: middlewares, bindings: bindings);
if (child.inheritParentPath) {
child = child.copyWith(
name: ('${route.path}/${child.path}').replaceAll(r'//', '/'));
}
addRoute(child);
}
}
void removeRoute(GetPage route) {
matcher.removeRoute(route.name);
tree.remove(route.path);
}
void removeRoutes(List<GetPage> routes) {
for (var route in routes) {
removeRoute(route);
}
}
RouteTreeResult? matchRoute(String path) {
final matchResult = matcher.matchRoute(path);
if (matchResult != null) {
final route = tree[matchResult.node.originalPath];
return RouteTreeResult(
route: route,
matchResult: matchResult,
);
}
return null;
}
}
/// A class representing the result of a route matching operation.
class MatchResult {
/// The route found that matches the result
final RouteNode node;
/// The current path of match, eg: adding 'user/:id' the match result for 'user/123' will be: 'user/123'
final String currentPath;
/// Route parameters eg: adding 'user/:id' the match result for 'user/123' will be: {id: 123}
final Map<String, String> parameters;
/// Route url parameters eg: adding 'user' the match result for 'user?foo=bar' will be: {foo: bar}
final Map<String, String> urlParameters;
MatchResult(this.node, this.parameters, this.currentPath,
{this.urlParameters = const {}});
@override
String toString() =>
'MatchResult(node: $node, currentPath: $currentPath, parameters: $parameters, urlParameters: $urlParameters)';
}
// A class representing a node in a routing tree.
class RouteNode {
String path;
String originalPath;
RouteNode? parent;
List<RouteNode> nodeSegments = [];
RouteNode(this.path, this.originalPath, {this.parent});
bool get isRoot => parent == null;
String get fullPath {
if (isRoot) {
return '/';
} else {
final parentPath = parent?.fullPath == '/' ? '' : parent?.fullPath;
return '$parentPath/$path';
}
}
bool get hasChildren => nodeSegments.isNotEmpty;
void addChild(RouteNode child) {
nodeSegments.add(child);
child.parent = this;
}
RouteNode? findChild(String name) {
return nodeSegments.firstWhereOrNull((node) => node.path == name);
}
bool matches(String name) {
return name == path || path == '*' || path.startsWith(':');
}
@override
String toString() =>
'RouteNode(name: $path, nodeSegments: $nodeSegments, fullPath: $fullPath )';
}
extension Foo<T> on Iterable<T> {
T? firstWhereOrNull(bool Function(T element) test) {
for (var element in this) {
if (test(element)) return element;
}
return null;
}
}
... ...
... ... @@ -185,6 +185,7 @@ class GetObserver extends NavigatorObserver {
}
}
//TODO: Use copyWith, and remove mutate variables
class Routing {
String current;
String previous;
... ...
import 'package:flutter/foundation.dart';
import '../../../route_manager.dart';
import '../../../get.dart';
@immutable
class RouteDecoder {
... ... @@ -14,9 +14,9 @@ class RouteDecoder {
factory RouteDecoder.fromRoute(String location) {
var uri = Uri.parse(location);
final args = PageSettings(uri);
final decoder = (Get.rootController.routerDelegate as GetDelegate)
.matchRoute(location, arguments: args);
decoder.route = decoder.route?.copy(
final decoder =
(Get.rootController.rootDelegate).matchRoute(location, arguments: args);
decoder.route = decoder.route?.copyWith(
completer: null,
arguments: args,
parameters: args.params,
... ... @@ -57,10 +57,10 @@ class RouteDecoder {
}
void replaceArguments(Object? arguments) {
final _route = route;
if (_route != null) {
final index = currentTreeBranch.indexOf(_route);
currentTreeBranch[index] = _route.copy(arguments: arguments);
final newRoute = route;
if (newRoute != null) {
final index = currentTreeBranch.indexOf(newRoute);
currentTreeBranch[index] = newRoute.copyWith(arguments: arguments);
}
}
... ... @@ -86,7 +86,6 @@ class ParseRouteTree {
RouteDecoder matchRoute(String name, {PageSettings? 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);
var curPath = '/';
final cumulativePaths = <String>[
... ... @@ -106,7 +105,7 @@ class ParseRouteTree {
.where((element) => element.value != null)
///Prevent page be disposed
.map((e) => MapEntry(e.key, e.value!.copy(key: ValueKey(e.key))))
.map((e) => MapEntry(e.key, e.value!.copyWith(key: ValueKey(e.key))))
.toList();
final params = Map<String, String>.from(uri.queryParameters);
... ... @@ -120,7 +119,7 @@ class ParseRouteTree {
//copy parameters to all pages.
final mappedTreeBranch = treeBranch
.map(
(e) => e.value.copy(
(e) => e.value.copyWith(
parameters: {
if (e.value.parameters != null) ...e.value.parameters!,
...params,
... ... @@ -185,14 +184,28 @@ class ParseRouteTree {
for (var page in route.children) {
// Add Parent middlewares to children
final parentMiddlewares = [
if (page.middlewares != null) ...page.middlewares!,
if (route.middlewares != null) ...route.middlewares!
if (page.middlewares.isNotEmpty) ...page.middlewares,
if (route.middlewares.isNotEmpty) ...route.middlewares
];
final parentBindings = [
if (page.binding != null) page.binding!,
if (page.bindings.isNotEmpty) ...page.bindings,
if (route.bindings.isNotEmpty) ...route.bindings
];
final parentBinds = [
if (page.binds.isNotEmpty) ...page.binds,
if (route.binds.isNotEmpty) ...route.binds
];
result.add(
_addChild(
page,
parentPath,
parentMiddlewares,
parentBindings,
parentBinds,
),
);
... ... @@ -203,7 +216,16 @@ class ParseRouteTree {
parentPath,
[
...parentMiddlewares,
if (child.middlewares != null) ...child.middlewares!,
if (child.middlewares.isNotEmpty) ...child.middlewares,
],
[
...parentBindings,
if (child.binding != null) child.binding!,
if (child.bindings.isNotEmpty) ...child.bindings,
],
[
...parentBinds,
if (child.binds.isNotEmpty) ...child.binds,
],
));
}
... ... @@ -213,10 +235,19 @@ class ParseRouteTree {
/// Change the Path for a [GetPage]
GetPage _addChild(
GetPage origin, String parentPath, List<GetMiddleware> middlewares) {
return origin.copy(
GetPage origin,
String parentPath,
List<GetMiddleware> middlewares,
List<BindingsInterface> bindings,
List<Bind> binds,
) {
return origin.copyWith(
middlewares: middlewares,
name: (parentPath + origin.name).replaceAll(r'//', '/'),
name: origin.inheritParentPath
? (parentPath + origin.name).replaceAll(r'//', '/')
: origin.name,
bindings: bindings,
binds: binds,
// key:
);
}
... ...
... ... @@ -130,8 +130,8 @@ class MiddlewareRunner {
final List<GetMiddleware>? _middlewares;
List<GetMiddleware> _getMiddlewares() {
final _m = _middlewares ?? <GetMiddleware>[];
return _m
final newMiddleware = _middlewares ?? <GetMiddleware>[];
return List.of(newMiddleware)
..sort(
(a, b) => (a.priority ?? 0).compareTo(b.priority ?? 0),
);
... ... @@ -198,34 +198,33 @@ class PageRedirect {
GetPageRoute<T> getPageToRoute<T>(
GetPage rou, GetPage? unk, BuildContext context) {
while (needRecheck(context)) {}
final _r = (isUnknown ? unk : rou)!;
final r = (isUnknown ? unk : rou)!;
return GetPageRoute<T>(
page: _r.page,
parameter: _r.parameters,
alignment: _r.alignment,
title: _r.title,
maintainState: _r.maintainState,
routeName: _r.name,
settings: _r,
curve: _r.curve,
showCupertinoParallax: _r.showCupertinoParallax,
gestureWidth: _r.gestureWidth,
opaque: _r.opaque,
customTransition: _r.customTransition,
bindings: _r.bindings,
binding: _r.binding,
binds: _r.binds,
transitionDuration:
_r.transitionDuration ?? Get.defaultTransitionDuration,
page: r.page,
parameter: r.parameters,
alignment: r.alignment,
title: r.title,
maintainState: r.maintainState,
routeName: r.name,
settings: r,
curve: r.curve,
showCupertinoParallax: r.showCupertinoParallax,
gestureWidth: r.gestureWidth,
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,
r.reverseTransitionDuration ?? Get.defaultTransitionDuration,
// performIncomeAnimation: _r.performIncomeAnimation,
// performOutGoingAnimation: _r.performOutGoingAnimation,
transition: _r.transition,
popGesture: _r.popGesture,
fullscreenDialog: _r.fullscreenDialog,
middlewares: _r.middlewares,
transition: r.transition,
popGesture: r.popGesture,
fullscreenDialog: r.fullscreenDialog,
middlewares: r.middlewares,
);
}
... ... @@ -248,7 +247,7 @@ class PageRedirect {
addPageParameter(route!);
// No middlewares found return match.
if (match.route!.middlewares == null || match.route!.middlewares!.isEmpty) {
if (match.route!.middlewares.isEmpty) {
return false;
}
final newSettings = runner.runRedirect(settings!.name);
... ...
... ... @@ -4,14 +4,14 @@ import '../router_report.dart';
import 'default_route.dart';
class RouteReport extends StatefulWidget {
RouteReport({Key? key, required this.builder}) : super(key: key);
const RouteReport({Key? key, required this.builder}) : super(key: key);
final WidgetBuilder builder;
@override
_RouteReportState createState() => _RouteReportState();
RouteReportState createState() => RouteReportState();
}
class _RouteReportState extends State<RouteReport> with RouteReportMixin {
class RouteReportState extends State<RouteReport> with RouteReportMixin {
@override
void initState() {
RouterReportManager.instance.reportCurrentRoute(this);
... ...
... ... @@ -9,12 +9,13 @@ class RouterOutlet<TDelegate extends RouterDelegate<T>, T extends Object>
//keys
RouterOutlet.builder({
super.key,
TDelegate? delegate,
required this.builder,
}) : routerDelegate = delegate ?? Get.delegate<TDelegate, T>()!,
super();
}) : routerDelegate = delegate ?? Get.delegate<TDelegate, T>()!;
RouterOutlet({
Key? key,
TDelegate? delegate,
required Iterable<GetPage> Function(T currentNavStack) pickPages,
required Widget Function(
... ... @@ -24,6 +25,7 @@ class RouterOutlet<TDelegate extends RouterDelegate<T>, T extends Object>
)
pageBuilder,
}) : this.builder(
key: key,
builder: (context) {
final currentConfig = context.delegate.currentConfiguration as T?;
final rDelegate = context.delegate as TDelegate;
... ... @@ -37,11 +39,11 @@ class RouterOutlet<TDelegate extends RouterDelegate<T>, T extends Object>
delegate: delegate,
);
@override
_RouterOutletState<TDelegate, T> createState() =>
_RouterOutletState<TDelegate, T>();
RouterOutletState<TDelegate, T> createState() =>
RouterOutletState<TDelegate, T>();
}
class _RouterOutletState<TDelegate extends RouterDelegate<T>, T extends Object>
class RouterOutletState<TDelegate extends RouterDelegate<T>, T extends Object>
extends State<RouterOutlet<TDelegate, T>> {
RouterDelegate? delegate;
late ChildBackButtonDispatcher _backButtonDispatcher;
... ... @@ -80,7 +82,7 @@ class _RouterOutletState<TDelegate extends RouterDelegate<T>, T extends Object>
}
}
// class _RouterOutletState<TDelegate extends RouterDelegate<T>,
// class RouterOutletState<TDelegate extends RouterDelegate<T>,
//T extends Object>
// extends State<RouterOutlet<TDelegate, T>> {
// TDelegate get delegate => context.delegate as TDelegate;
... ... @@ -152,11 +154,11 @@ class GetRouterOutlet extends RouterOutlet<GetDelegate, RouteDecoder> {
delegate: delegate,
);
GetRouterOutlet.pickPages({
super.key,
Widget Function(GetDelegate delegate)? emptyWidget,
GetPage Function(GetDelegate delegate)? emptyPage,
required Iterable<GetPage> Function(RouteDecoder currentNavStack) pickPages,
bool Function(Route<dynamic>, dynamic)? onPopPage,
GlobalKey<NavigatorState>? key,
GetDelegate? delegate,
}) : super(
pageBuilder: (context, rDelegate, pages) {
... ... @@ -179,13 +181,14 @@ class GetRouterOutlet extends RouterOutlet<GetDelegate, RouteDecoder> {
key: key,
);
}
return (emptyWidget?.call(rDelegate) ?? SizedBox.shrink());
return (emptyWidget?.call(rDelegate) ?? const SizedBox.shrink());
},
pickPages: pickPages,
delegate: delegate ?? Get.rootController.rootDelegate,
);
GetRouterOutlet.builder({
super.key,
required Widget Function(
BuildContext context,
)
... ...
... ... @@ -7,88 +7,10 @@ import '../../../get_core/get_core.dart';
import '../../get_navigation.dart';
typedef OnTap = void Function(GetSnackBar snack);
typedef OnHover = void Function(GetSnackBar snack, SnackHoverState snackHoverState);
typedef SnackbarStatusCallback = void Function(SnackbarStatus? status);
@Deprecated('use GetSnackBar')
class GetBar extends GetSnackBar {
GetBar({
Key? key,
String? title,
String? message,
Widget? titleText,
Widget? messageText,
Widget? icon,
bool shouldIconPulse = true,
double? maxWidth,
EdgeInsets margin = const EdgeInsets.all(0.0),
EdgeInsets padding = const EdgeInsets.all(16),
double borderRadius = 0.0,
Color? borderColor,
double borderWidth = 1.0,
Color backgroundColor = const Color(0xFF303030),
Color? leftBarIndicatorColor,
List<BoxShadow>? boxShadows,
Gradient? backgroundGradient,
Widget? mainButton,
OnTap? onTap,
Duration? duration,
bool isDismissible = true,
DismissDirection? dismissDirection,
bool showProgressIndicator = false,
AnimationController? progressIndicatorController,
Color? progressIndicatorBackgroundColor,
Animation<Color>? progressIndicatorValueColor,
SnackPosition snackPosition = SnackPosition.bottom,
SnackStyle snackStyle = SnackStyle.floating,
Curve forwardAnimationCurve = Curves.easeOutCirc,
Curve reverseAnimationCurve = Curves.easeOutCirc,
Duration animationDuration = const Duration(seconds: 1),
double barBlur = 0.0,
double overlayBlur = 0.0,
Color overlayColor = Colors.transparent,
Form? userInputForm,
SnackbarStatusCallback? snackbarStatus,
}) : super(
key: key,
title: title,
message: message,
titleText: titleText,
messageText: messageText,
icon: icon,
shouldIconPulse: shouldIconPulse,
maxWidth: maxWidth,
margin: margin,
padding: padding,
borderRadius: borderRadius,
borderColor: borderColor,
borderWidth: borderWidth,
backgroundColor: backgroundColor,
leftBarIndicatorColor: leftBarIndicatorColor,
boxShadows: boxShadows,
backgroundGradient: backgroundGradient,
mainButton: mainButton,
onTap: onTap,
duration: duration,
isDismissible: isDismissible,
dismissDirection: dismissDirection,
showProgressIndicator: showProgressIndicator,
progressIndicatorController: progressIndicatorController,
progressIndicatorBackgroundColor: progressIndicatorBackgroundColor,
progressIndicatorValueColor: progressIndicatorValueColor,
snackPosition: snackPosition,
snackStyle: snackStyle,
forwardAnimationCurve: forwardAnimationCurve,
reverseAnimationCurve: reverseAnimationCurve,
animationDuration: animationDuration,
barBlur: barBlur,
overlayBlur: overlayBlur,
overlayColor: overlayColor,
userInputForm: userInputForm,
snackbarStatus: snackbarStatus,
);
}
class GetSnackBar extends StatefulWidget {
/// A callback for you to listen to the different Snack status
final SnackbarStatusCallback? snackbarStatus;
... ... @@ -150,6 +72,9 @@ class GetSnackBar extends StatefulWidget {
/// An alternative to [mainButton]
final OnTap? onTap;
/// A callback that registers the user's hover anywhere over the Snackbar.
final OnHover? onHover;
/// How long until Snack will hide itself (be dismissed).
/// To make it indefinite, leave it null.
final Duration? duration;
... ... @@ -259,6 +184,7 @@ class GetSnackBar extends StatefulWidget {
this.backgroundGradient,
this.mainButton,
this.onTap,
this.onHover,
this.duration,
this.isDismissible = true,
this.dismissDirection,
... ... @@ -293,11 +219,11 @@ class GetSnackBarState extends State<GetSnackBar>
AnimationController? _fadeController;
late Animation<double> _fadeAnimation;
final Widget _emptyWidget = SizedBox(width: 0.0, height: 0.0);
final Widget _emptyWidget = const SizedBox(width: 0.0, height: 0.0);
final double _initialOpacity = 1.0;
final double _finalOpacity = 0.4;
final Duration _pulseAnimationDuration = Duration(seconds: 1);
final Duration _pulseAnimationDuration = const Duration(seconds: 1);
late bool _isTitlePresent;
late double _messageTopMargin;
... ... @@ -513,9 +439,9 @@ You need to either use message[String], or messageText[Widget] or define a userI
padding: const EdgeInsets.only(
left: 8.0, right: 8.0, bottom: 8.0, top: 16.0),
child: FocusScope(
child: widget.userInputForm!,
node: _focusNode,
autofocus: true,
child: widget.userInputForm!,
),
),
);
... ... @@ -581,7 +507,7 @@ You need to either use message[String], or messageText[Widget] or define a userI
child: widget.titleText ??
Text(
widget.title ?? "",
style: TextStyle(
style: const TextStyle(
fontSize: 16.0,
color: Colors.white,
fontWeight: FontWeight.bold,
... ... @@ -600,8 +526,8 @@ You need to either use message[String], or messageText[Widget] or define a userI
child: widget.messageText ??
Text(
widget.message ?? "",
style:
TextStyle(fontSize: 14.0, color: Colors.white),
style: const TextStyle(
fontSize: 14.0, color: Colors.white),
),
),
],
... ... @@ -657,3 +583,6 @@ enum SnackPosition { top, bottom }
/// Indicates if snack will be attached to the edge of the screen or not
enum SnackStyle { floating, grounded }
/// Indicates if the mouse entered or exited
enum SnackHoverState { entered, exited }
\ No newline at end of file
... ...
... ... @@ -220,15 +220,15 @@ class SnackbarController {
],
OverlayEntry(
builder: (context) => Semantics(
focused: false,
container: true,
explicitChildNodes: true,
child: AlignTransition(
alignment: _animation,
child: snackbar.isDismissible
? _getDismissibleSnack(child)
: _getSnackbarContainer(child),
),
focused: false,
container: true,
explicitChildNodes: true,
),
maintainState: false,
opaque: false,
... ... @@ -238,11 +238,15 @@ class SnackbarController {
Widget _getBodyWidget() {
return Builder(builder: (_) {
return GestureDetector(
child: snackbar,
onTap: snackbar.onTap != null
? () => snackbar.onTap?.call(snackbar)
: null,
return MouseRegion(
onEnter: (_) => snackbar.onHover?.call(snackbar, SnackHoverState.entered),
onExit: (_) => snackbar.onHover?.call(snackbar, SnackHoverState.exited),
child: GestureDetector(
child: snackbar,
onTap: snackbar.onTap != null
? () => snackbar.onTap?.call(snackbar)
: null,
),
);
});
}
... ...
... ... @@ -226,11 +226,11 @@ Worker debounce<T>(
void Function()? onDone,
bool? cancelOnError,
}) {
final _debouncer =
final newDebouncer =
Debouncer(delay: time ?? const Duration(milliseconds: 800));
StreamSubscription sub = listener.listen(
(event) {
_debouncer(() {
newDebouncer(() {
callback(event);
});
},
... ...
... ... @@ -22,6 +22,7 @@ class GetX<T extends GetLifeCycleMixin> extends StatefulWidget {
final String? tag;
const GetX({
super.key,
this.tag,
required this.builder,
this.global = true,
... ...
... ... @@ -32,7 +32,7 @@ mixin StateMixin<T> on ListNotifier {
void _fillInitialStatus() {
_status = (_value == null || _value!._isEmpty())
? GetStatus<T>.loading()
: GetStatus<T>.success(_value!);
: GetStatus<T>.success(_value as T);
}
GetStatus<T> get status {
... ... @@ -71,7 +71,7 @@ mixin StateMixin<T> on ListNotifier {
}
}
void futurize(Future<T> Function() body,
void futurize(Future<T> Function() body,
{T? initialData, String? errorMessage, bool useEmpty = true}) {
final compute = body;
_value ??= initialData;
... ... @@ -231,12 +231,12 @@ extension StateExt<T> on StateMixin<T> {
: Center(child: Text('A error occurred: ${status.errorMessage}'));
} else if (status.isEmpty) {
return onEmpty ??
SizedBox.shrink(); // Also can be widget(null); but is risky
const SizedBox.shrink(); // Also can be widget(null); but is risky
} else if (status.isSuccess) {
return widget(value);
} else if (status.isCustom) {
return onCustom?.call(_) ??
SizedBox.shrink(); // Also can be widget(null); but is risky
const SizedBox.shrink(); // Also can be widget(null); but is risky
}
return widget(value);
});
... ...
... ... @@ -24,7 +24,7 @@ abstract class ObxWidget extends ObxStatelessWidget {
class Obx extends ObxWidget {
final WidgetCallback builder;
const Obx(this.builder);
const Obx(this.builder, {super.key});
@override
Widget build(BuildContext context) {
... ...