Showing
82 changed files
with
1221 additions
and
3096 deletions
Too many changes to show.
To preserve performance only 82 of 82+ files are displayed.
@@ -13,7 +13,7 @@ jobs: | @@ -13,7 +13,7 @@ jobs: | ||
13 | #The type of machine to run the job on. [windows,macos, ubuntu , self-hosted] | 13 | #The type of machine to run the job on. [windows,macos, ubuntu , self-hosted] |
14 | defaults: | 14 | defaults: |
15 | run: | 15 | run: |
16 | - working-directory: getx/ | 16 | + working-directory: ./ |
17 | runs-on: ubuntu-latest | 17 | runs-on: ubuntu-latest |
18 | #sequence of tasks called | 18 | #sequence of tasks called |
19 | steps: | 19 | steps: |
.vscode/launch.json
0 → 100644
1 | +{ | ||
2 | + // Use o IntelliSense para aprender sobre possíveis atributos. | ||
3 | + // Passe o mouse para ver as descrições dos atributos existentes. | ||
4 | + // Para obter mais informações, visite: https://go.microsoft.com/fwlink/?linkid=830387 | ||
5 | + "version": "0.2.0", | ||
6 | + "configurations": [ | ||
7 | + { | ||
8 | + "name": "getx", | ||
9 | + "cwd": "getx", | ||
10 | + "request": "launch", | ||
11 | + "type": "dart" | ||
12 | + }, | ||
13 | + { | ||
14 | + "name": "example debug", | ||
15 | + "cwd": "getx/example", | ||
16 | + "request": "launch", | ||
17 | + "flutterMode": "debug", | ||
18 | + "type": "dart" | ||
19 | + }, | ||
20 | + { | ||
21 | + "name": "example profile", | ||
22 | + "cwd": "getx/example", | ||
23 | + "request": "launch", | ||
24 | + "flutterMode": "profile", | ||
25 | + "type": "dart" | ||
26 | + }, | ||
27 | + { | ||
28 | + "name": "example release", | ||
29 | + "cwd": "getx/example", | ||
30 | + "request": "launch", | ||
31 | + "flutterMode": "release", | ||
32 | + "type": "dart" | ||
33 | + }, | ||
34 | + { | ||
35 | + "name": "get_core", | ||
36 | + "cwd": "packages/get_core", | ||
37 | + "request": "launch", | ||
38 | + "type": "dart" | ||
39 | + }, | ||
40 | + { | ||
41 | + "name": "get_instance", | ||
42 | + "cwd": "packages/get_instance", | ||
43 | + "request": "launch", | ||
44 | + "type": "dart" | ||
45 | + }, | ||
46 | + { | ||
47 | + "name": "get_navigation", | ||
48 | + "cwd": "packages/get_navigation", | ||
49 | + "request": "launch", | ||
50 | + "type": "dart" | ||
51 | + }, | ||
52 | + { | ||
53 | + "name": "get_rx", | ||
54 | + "cwd": "packages/get_rx", | ||
55 | + "request": "launch", | ||
56 | + "type": "dart" | ||
57 | + }, | ||
58 | + { | ||
59 | + "name": "get_state_manager", | ||
60 | + "cwd": "packages/get_state_manager", | ||
61 | + "request": "launch", | ||
62 | + "type": "dart" | ||
63 | + }, | ||
64 | + { | ||
65 | + "name": "get_test", | ||
66 | + "cwd": "packages/get_test", | ||
67 | + "request": "launch", | ||
68 | + "type": "dart" | ||
69 | + }, | ||
70 | + { | ||
71 | + "name": "get_utils", | ||
72 | + "cwd": "packages/get_utils", | ||
73 | + "request": "launch", | ||
74 | + "type": "dart" | ||
75 | + } | ||
76 | + ] | ||
77 | +} |
1 | -## [3.12.2] | 1 | +## [3.13.1] |
2 | +- Remove spaces whitespaces from dart files | ||
3 | +- | ||
4 | +## [3.13.0] | ||
2 | - Fix typos on code and docs (@wbemanuel and @Goddchen) | 5 | - Fix typos on code and docs (@wbemanuel and @Goddchen) |
3 | - Improve: typedef to GetBuilder and Getx widgets | 6 | - Improve: typedef to GetBuilder and Getx widgets |
4 | - Improve behaviour of null route on lastest flutter version (@FiercestT) | 7 | - Improve behaviour of null route on lastest flutter version (@FiercestT) |
@@ -8,7 +11,6 @@ | @@ -8,7 +11,6 @@ | ||
8 | - Transition.native use default Flutter transitions | 11 | - Transition.native use default Flutter transitions |
9 | - Added Get.testMode to use contextless elements on unit tests | 12 | - Added Get.testMode to use contextless elements on unit tests |
10 | - Added Get.appUpdate and improve Get.forceAppUpdate | 13 | - Added Get.appUpdate and improve Get.forceAppUpdate |
11 | -- | ||
12 | 14 | ||
13 | ## [3.12.1] | 15 | ## [3.12.1] |
14 | - Remove spaces whitespaces from dart files | 16 | - Remove spaces whitespaces from dart files |
getx/.gitignore
deleted
100644 → 0
1 | -# See https://www.dartlang.org/guides/libraries/private-files | ||
2 | - | ||
3 | -# See https://www.dartlang.org/guides/libraries/private-files | ||
4 | - | ||
5 | -# Files and directories created by pub | ||
6 | -.dart_tool/ | ||
7 | -.packages | ||
8 | -build/ | ||
9 | -# If you're building an application, you may want to check-in your pubspec.lock | ||
10 | -pubspec.lock | ||
11 | -.pub/ | ||
12 | - | ||
13 | -# Directory created by dartdoc | ||
14 | -# If you don't generate documentation locally you can remove this line. | ||
15 | -doc/api/ | ||
16 | - | ||
17 | -# Avoid committing generated Javascript files: | ||
18 | -*.dart.js | ||
19 | -*.info.json # Produced by the --dump-info flag. | ||
20 | -*.js # When generated by dart2js. Don't specify *.js if your | ||
21 | - # project includes source files written in JavaScript. | ||
22 | -*.js_ | ||
23 | -*.js.deps | ||
24 | -*.js.map | ||
25 | - | ||
26 | -# Files and directories created when test or run example | ||
27 | -example/android/local.properties | ||
28 | -example/ios/ | ||
29 | -example/.dart_tool/ | ||
30 | -example/.packages | ||
31 | - | ||
32 | -# IntelliJ | ||
33 | -*.iml | ||
34 | -.idea/* | ||
35 | -#.idea/workspace.xml | ||
36 | -#.idea/tasks.xml | ||
37 | -#.idea/gradle.xml | ||
38 | -#.idea/assetWizardSettings.xml | ||
39 | -#.idea/dictionaries | ||
40 | -#.idea/libraries | ||
41 | -#.idea/caches | ||
42 | - | ||
43 | -# User-specific stuff | ||
44 | -.idea/**/workspace.xml | ||
45 | -.idea/**/tasks.xml | ||
46 | -.idea/**/dictionaries | ||
47 | -.idea/**/shelf | ||
48 | - | ||
49 | -# Sensitive or high-churn files | ||
50 | -.idea/**/dataSources/ | ||
51 | -.idea/**/dataSources.ids | ||
52 | -.idea/**/dataSources.local.xml | ||
53 | -.idea/**/sqlDataSources.xml | ||
54 | -.idea/**/dynamic.xml | ||
55 | -.idea/**/uiDesigner.xml | ||
56 | -.idea/**/dbnavigator.xml | ||
57 | - | ||
58 | -# Gradle | ||
59 | -.idea/**/gradle.xml | ||
60 | -.idea/**/libraries | ||
61 | - | ||
62 | -# Android Studio Navigation editor temp files | ||
63 | -.navigation/ | ||
64 | - | ||
65 | -# Android Studio captures folder | ||
66 | -captures/ | ||
67 | - | ||
68 | -# External native build folder generated in Android Studio 2.2 and later | ||
69 | -.externalNativeBuild | ||
70 | - | ||
71 | -### https://raw.github.com/github/gitignore/80a8803b004013d17291196825a327b9e871f009/Global/VisualStudioCode.gitignore | ||
72 | -.vscode/* | ||
73 | -!.vscode/settings.json | ||
74 | -!.vscode/tasks.json | ||
75 | -!.vscode/launch.json | ||
76 | -!.vscode/extensions.json | ||
77 | - | ||
78 | -example/macos/Flutter/ephemeral/Flutter-Generated.xcconfig | ||
79 | - | ||
80 | -example/macos/Flutter/ephemeral/ | ||
81 | - | ||
82 | -example/macos/Flutter/GeneratedPluginRegistrant.swift |
getx/LICENSE
deleted
100644 → 0
1 | -MIT License | ||
2 | - | ||
3 | -Copyright (c) 2019 Jonny Borges | ||
4 | - | ||
5 | -Permission is hereby granted, free of charge, to any person obtaining a copy | ||
6 | -of this software and associated documentation files (the "Software"), to deal | ||
7 | -in the Software without restriction, including without limitation the rights | ||
8 | -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
9 | -copies of the Software, and to permit persons to whom the Software is | ||
10 | -furnished to do so, subject to the following conditions: | ||
11 | - | ||
12 | -The above copyright notice and this permission notice shall be included in all | ||
13 | -copies or substantial portions of the Software. | ||
14 | - | ||
15 | -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
18 | -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
20 | -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
21 | -SOFTWARE. |
getx/README-es.md
deleted
100644 → 0
1 | - | ||
2 | - | ||
3 | -*Idiomas: Español (este archivo), [Inglés](README.md), [Portugués de Brasil](README.pt-br.md), [Polaco](README.pl.md).* | ||
4 | - | ||
5 | -[](https://pub.dev/packages/get) | ||
6 | - | ||
7 | -[](https://pub.dev/packages/effective_dart) | ||
8 | -[](https://discord.com/invite/9Hpt99N) | ||
9 | -[](https://communityinviter.com/apps/getxworkspace/getx) | ||
10 | -[](https://t.me/joinchat/PhdbJRmsZNpAqSLJL6bH7g) | ||
11 | -<a href="https://github.com/Solido/awesome-flutter"> | ||
12 | - <img alt="Awesome Flutter" src="https://img.shields.io/badge/Awesome-Flutter-blue.svg?longCache=true&style=flat-square" /> | ||
13 | -</a> | ||
14 | -<a href="https://www.buymeacoffee.com/jonataslaw" target="_blank"><img src="https://i.imgur.com/aV6DDA7.png" alt="Buy Me A Coffee" style="height: 41px !important;width: 174px !important; box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;" > </a> | ||
15 | - | ||
16 | - | ||
17 | - | ||
18 | -<h3>Lamentamos la inconsistencia en la traducción. El paquete GetX se actualiza con bastante frecuencia y es posible que las traducciones a documentos no sean tan rápidas. Entonces, para que esta documentación aún tenga todo el contenido, dejaré aquí todos los textos nuevos sin traducir (considero que es mejor tener los documentos en inglés que no tenerlos), por lo que si alguien quiere traducir, sería de gran ayuda 😁</h3> | ||
19 | - | ||
20 | -- [Communication and support channels:](#communication-and-support-channels) | ||
21 | -- [Sobre GetX](#sobre-getx) | ||
22 | -- [Como contribuir](#como-contribuir) | ||
23 | -- [Instalando](#installing) | ||
24 | -- [Proyecto Counter en GetX](#proyeto-counter-no-getx) | ||
25 | -- [Los tres pilares](#los-tres-pilares) | ||
26 | - - [Gestión del Estado](#gestión-del-estado) | ||
27 | - - [STATE_MANAGER Reactivo](#reactivo-state_manager) | ||
28 | - - [Más detalles sobre la gestión del estado.](#más-detalles-sobre-la-gestión-del-estado) | ||
29 | - - [Explicación en video sobre state management](#video-explanation-about-state-management) | ||
30 | - - [Gestión de Rutas](#gestión-de-rutas) | ||
31 | - - [Más detalles sobre la gestión de rutas.](#más-detalles-sobre-la-gestión-de-rutas) | ||
32 | - - [Explicación del video](#video-explanation) | ||
33 | - - [Gestión de dependencias](#gestión-de-dependencias) | ||
34 | - - [Más detalles sobre la gestión de dependencias.](#más-detalles-sobre-la-gestión-de-dependencias) | ||
35 | -- [Utilidades](#utils) | ||
36 | - - [Cambiar de tema](#cambiar-de-tema) | ||
37 | - - [Otras API avanzadas y configuraciones manuales](#otras-api-avanzadas-y-configuraciones-manuales) | ||
38 | - - [Configuraciones globales opcionales](#configuraciones-globales-opcionales) | ||
39 | - - [Explicación en video de Other GetX Features](#video-explanation-of-other-getx-features) | ||
40 | -- [Rompiendo cambios desde 2.0](#rompiendo-cambios-desde-20) | ||
41 | -- [¿Por qué Getx?](#por-qué-getx) | ||
42 | - | ||
43 | -# Communication and support channels: | ||
44 | - | ||
45 | -[**Slack (Inglés)**](https://communityinviter.com/apps/getxworkspace/getx) | ||
46 | - | ||
47 | -[**Discord (Ingles y Portugués)**](https://discord.com/invite/9Y3wK9) | ||
48 | - | ||
49 | -[**Telegram (Portugués)**](https://t.me/joinchat/PhdbJRmsZNpAqSLJL6bH7g) | ||
50 | - | ||
51 | -# Sobre GetX | ||
52 | - | ||
53 | -- GetX es una solución extra ligera y potente para Flutter. Combina gestión de estádo de alto rendimiento, inyección de dependencia inteligente y gestión de rutas, de forma rápida y práctica. | ||
54 | - | ||
55 | -- GetX tiene 3 principios básicos, esto significa que esta es la prioridad para todos los recursos de la biblioteca. | ||
56 | - **PERFORMANCE:** GetX se centra en el rendimiento y el consumo mínimo de recursos. Los puntos de referencia casi siempre no son importantes en el mundo real, pero si lo desea, aquí hay un indicador de consumo.([benchmarks](https://github.com/jonataslaw/benchmarks)), donde GetX lo hace mejor que otros enfoques de gestión estatal, por ejemplo. La diferencia no es grande, pero muestra nuestra preocupación por no desperdiciar sus recursos. | ||
57 | - **PRODUCTIVITY:** GetX utiliza una sintaxis fácil y agradable. | ||
58 | - **ORGANIZATION:** GetX permite el desacoplamiento total de la vista de la lógica empresarial. | ||
59 | - | ||
60 | -* GetX ahorrará horas de desarrollo y extraerá el máximo rendimiento que su aplicación puede ofrecer, siendo fácil para los principiantes y precisa para los expertos. Navega sin contexto, abre diálogos, snackbars o bottomsheets desde cualquier lugar de tu código, gestiona estados e inyecta dependencias de forma fácil y práctica. Get es seguro, estable, actualizado y ofrece una amplia gama de API que no están presentes en el marco predeterminado. | ||
61 | - | ||
62 | -- GetX no es bloated. Tiene una multitud de características que le permiten comenzar a programar sin preocuparse por nada, pero cada una de estas características se encuentran en contenedores separados y solo se inician después de su uso. Si solo usa State Management, solo se compilará State Management. Si solo usa rutas, no se compilará nada de la administración estatal. Puede compilar el repositorio de referencia y verá que al usar solo la administración de estado de Get, la aplicación compilada con Get se ha vuelto más pequeña que todas las demás aplicaciones que solo tienen la administración de estado de otros paquetes, porque nada que no se use se compilará en su código, y cada solución GetX fue diseñada para ser muy liviana. El mérito aquí también proviene del movimiento del árbol de Flutter, que es increíble y logra eliminar los recursos no utilizados como ningún otro marco lo hace. | ||
63 | - | ||
64 | -**GetX hace que su desarrollo sea productivo, pero ¿quiere hacerlo aún más productivo? [Agregue la extensión a su VSCode](https://marketplace.visualstudio.com/items?itemName=get-snippets.get-snippets)** | ||
65 | - | ||
66 | -# Como contribuir | ||
67 | - | ||
68 | -_¿Quieres contribuir al proyecto? Estaremos orgullosos de destacarte como uno de nuestros colaboradores. Aquí hay algunos puntos en los que puede contribuir y hacer que GetX (y Flutter) sea aún mejor._ | ||
69 | - | ||
70 | -- Ayudando a traducir el archivo Léame a otros idiomas. | ||
71 | - | ||
72 | -- Agregar documentación al archivo Léame (ni siquiera la mitad de las funciones de GetX han sido documentadas todavía). | ||
73 | - | ||
74 | -- Escriba artículos o haga videos que enseñen cómo usar GetX (se insertarán en el archivo Léame y en el futuro en nuestro Wiki). | ||
75 | - | ||
76 | -- Ofreciendo PRs para código/pruebas. | ||
77 | - | ||
78 | -- Incluyendo nuevas funciones. | ||
79 | - | ||
80 | -# Installing | ||
81 | - | ||
82 | -Add Get to your pubspec.yaml file: | ||
83 | - | ||
84 | -```yaml | ||
85 | -dependencies: | ||
86 | - get: | ||
87 | -``` | ||
88 | - | ||
89 | -Importar archivos get que se utilizarán: | ||
90 | - | ||
91 | -```dart | ||
92 | -import 'package:get/get.dart'; | ||
93 | -``` | ||
94 | - | ||
95 | -# Proyecto Counter no GetX | ||
96 | - | ||
97 | -Vea una explicación más detallada de la administración del estado [aquí](./documentation/es_ES/state_management.md). Allí verá más ejemplos y también la diferencia entre el Gestión del Estado simple y el Gestión del Estado reactivo | ||
98 | - | ||
99 | -El proyecto "contador" creado por defecto en un nuevo proyecto en Flutter tiene más de 100 líneas (con comentarios). Para mostrar el poder de GetX, demostraré cómo hacer un "contador" cambiando el estado con cada clic, cambiando de página y compartiendo el estado entre pantallas, todo de manera organizada, separando la vista de la lógica de negocio, SOLO 26 LÍNEAS DE CÓDIGO INCLUIDOS COMENTARIOS. | ||
100 | - | ||
101 | -- Paso 1: | ||
102 | - Agregue "Get" antes de su materialApp, convirtiéndolo en GetMaterialApp | ||
103 | - | ||
104 | -```dart | ||
105 | -void main() => runApp(GetMaterialApp(home: Home())); | ||
106 | -``` | ||
107 | - | ||
108 | -**Nota**: esto no modifica el MaterialApp del Flutter, GetMaterialApp no es una MaterialApp modificado, es solo un Widget preconfigurado, que tiene como child un MaterialApp por defecto. Puede configurar esto manualmente, pero definitivamente no es necesario. GetMaterialApp creará rutas, las inyectará, inyectará traducciones, inyectará todo lo que necesita para la navegación de rutas. Si usa Get solo para la gestión de estado o dependencias, no es necesario usar GetMaterialApp. GetMaterialApp es necesario para rutas, snackbars, internacionalización, bottomSheets, diálogos y APIs de alto nivel relacionadas con rutas y ausencia de contexto. | ||
109 | - | ||
110 | -**Note²:** Este paso solo es necesario si vas a usar route management (`Get.to()`, `Get.back()` y así). Si no lo va a usar, no es necesario que realice el paso 1 | ||
111 | - | ||
112 | -- Paso 2: | ||
113 | - Cree su clase con la lógica de negocio colocando todas las variables, métodos y controladores dentro de ella. Puede hacer que cualquier variable sea observable usando un simple ".obs". | ||
114 | - | ||
115 | -```dart | ||
116 | -class Controller extends GetxController { | ||
117 | - var count = 0.obs; | ||
118 | - increment() => count.value++; | ||
119 | -} | ||
120 | -``` | ||
121 | - | ||
122 | -- Paso 3: | ||
123 | - Cree su vista, use StatelessWidget y ahorre algo de RAM, con GetX ya no necesitará usar StatefulWidget. | ||
124 | - | ||
125 | -```dart | ||
126 | -class Home extends StatelessWidget { | ||
127 | - | ||
128 | - // Cree una instancia de su clase usando Get.put() para que esté disponible para todas las rutas "secundarias" allí. | ||
129 | - final Controller c = Get.put(Controller()); | ||
130 | - | ||
131 | - @override | ||
132 | - Widget build(context) => Scaffold( | ||
133 | - // Utilice Obx(()=> para actualizar Text() siempre que se cambie el recuento. | ||
134 | - appBar: AppBar(title: Obx(() => Text("Clicks: " + c.count.string))), | ||
135 | - | ||
136 | - // Reemplace el Navigator.push de 8 líneas por un simple Get.to(). No necesitas contexto | ||
137 | - body: Center(child: RaisedButton( | ||
138 | - child: Text("Go to Other"), onPressed: () => Get.to(Other()))), | ||
139 | - floatingActionButton: | ||
140 | - FloatingActionButton(child: Icon(Icons.add), onPressed: c.increment)); | ||
141 | -} | ||
142 | - | ||
143 | -class Other extends StatelessWidget { | ||
144 | - // Puede pedirle a Get que busque un controlador que está siendo utilizado por otra página y le redirija a él. | ||
145 | - final Controller c = Get.find(); | ||
146 | - | ||
147 | - @override | ||
148 | - Widget build(context){ | ||
149 | - // Acceder a la variable de recuento actualizada | ||
150 | - return Scaffold(body: Center(child: Text(c.count.string))); | ||
151 | - } | ||
152 | -} | ||
153 | - | ||
154 | -``` | ||
155 | - | ||
156 | -Resultado: | ||
157 | - | ||
158 | - | ||
159 | - | ||
160 | -Este es un proyecto simple pero ya deja en claro cuán poderoso es GetX. A medida que su proyecto crezca, esta diferencia se volverá más significativa. GetX fue diseñado para trabajar con equipos, pero también simplifica el trabajo de un desarrollador individual. Mejore sus plazos, entregue todo a tiempo, sin perder rendimiento. GetX no es para todos, pero si te identificaste con esa frase, ¡GET es para ti! | ||
161 | - | ||
162 | -# Los tres pilares | ||
163 | - | ||
164 | -## Gestión del Estado | ||
165 | - | ||
166 | -Actualmente hay varios State Managers para Flutter. Sin embargo, con la mayoría de ellos implica utilizar ChangeNotifier para actualizar widgets y este es un enfoque malo y muy malo para el rendimiento de aplicaciones medianas o grandes. Puede verificar en la documentación oficial de Flutter que [ChangeNotifier debe usarse con 1 o un máximo de 2 listeners](https://api.Flutter.dev/Flutter/foundation/ChangeNotifier-class.html), por lo que es prácticamente inutilizable para cualquier aplicación mediana o grande. | ||
167 | - | ||
168 | -GetX no es mejor ni peor que cualquier otro gestor de estado, pero debe analizar estos puntos, así como los puntos que se mencionan a continuación, para elegir entre usar GetX en forma pura (vanilla) o usarlo junto con otro gestor de estado. | ||
169 | - | ||
170 | -Definitivamente, GetX no es enemigo de ningún otro gestor de estado, porque GetX es más bien un microframework, no solo un gestor de estado, y se puede usar solo o en combinación con ellos. | ||
171 | - | ||
172 | -### Reactivo STATE_MANAGER | ||
173 | - | ||
174 | -La programación reactiva puede alienar a muchas personas porque se dice que es complicada. GetX convierte la programación reactiva en algo tan simple que puede ser aprendido y utilizado por aquellos que comenzaron en ese mismo momento en Flutter. No, no necesitará crear StreamControllers. Tampoco necesitará crear un StreamBuilder para cada variable. No necesitará crear una clase para cada estado. No necesitará crear un get para un valor inicial. La programación reactiva con GetX es tan fácil como usar setState (¡o incluso más fácil!). | ||
175 | - | ||
176 | -Imaginemos que tiene una variable "name" y desea que cada vez que la modifique, todos los widgets que la usan cambien automáticamente. | ||
177 | - | ||
178 | -Ej. esta es tu variable "name": | ||
179 | - | ||
180 | -```dart | ||
181 | -var name = 'Jonatas Borges'; | ||
182 | -``` | ||
183 | - | ||
184 | -Para que sea observable, solo necesita agregar ".obs" al final: | ||
185 | - | ||
186 | -```dart | ||
187 | -var name = 'Jonatas Borges'.obs; | ||
188 | -``` | ||
189 | - | ||
190 | -¿StreamBuilder? ¿initialValue? ¿builder? No, solo necesitas jugar con esta variable dentro de un widget Obx. | ||
191 | - | ||
192 | -```dart | ||
193 | -Obx(() => Text (controller.name)); | ||
194 | -``` | ||
195 | - | ||
196 | -### Más detalles sobre la gestión del estado. | ||
197 | - | ||
198 | -**Vea una explicación más detallada de la administración del estado [aquí](./documentation/es_ES/state_management.md). Allí verá más ejemplos y también la diferencia entre el Gestión del Estado simple y el Gestión del Estado reactivo** | ||
199 | - | ||
200 | -### Explicación en video sobre state management | ||
201 | - | ||
202 | -Darwin Morocho hizo una increíble serie de videos sobre state management! Link: [Complete GetX State Management](https://www.youtube.com/watch?v=PTjj0DFK8BA&list=PLV0nOzdUS5XtParoZLgKoVwNSK9zROwuO) | ||
203 | - | ||
204 | -Obtendrá una buena idea de la potencia de GetX. | ||
205 | - | ||
206 | -## Gestión de Rutas | ||
207 | - | ||
208 | -Para navegar a una nueva pantalla: | ||
209 | - | ||
210 | -```dart | ||
211 | -Get.to(NextScreen()); | ||
212 | -``` | ||
213 | - | ||
214 | -Para cerrar snackbars, dialogs, bottomsheets o cualquier cosa que normalmente cierre con Navigator.pop(contexto); | ||
215 | - | ||
216 | -```dart | ||
217 | -Get.back(); | ||
218 | -``` | ||
219 | - | ||
220 | -Para ir a la siguiente pantalla, sin opción a volver (util por ejemplo en SplashScreens, LoginScreen, etc.) | ||
221 | - | ||
222 | -```dart | ||
223 | -Get.off(NextScreen()); | ||
224 | -``` | ||
225 | - | ||
226 | -Para ir a la siguiente pantalla y cancelar todas las rutas anteriores (útil en carritos de compras, encuestas y exámenes) | ||
227 | - | ||
228 | -```dart | ||
229 | -Get.offAll(NextScreen()); | ||
230 | -``` | ||
231 | - | ||
232 | -Para navegar a la siguiente ruta y recibir o actualizar datos tan pronto como se regrese de ella: | ||
233 | - | ||
234 | -```dart | ||
235 | -var data = await Get.to(Payment()); | ||
236 | -``` | ||
237 | - | ||
238 | -### Más detalles sobre la gestión de rutas. | ||
239 | - | ||
240 | -**Vea una explicación más detallada de la Gestión de Rutas [aquí](./documentation/es_ES/route_management.md).** | ||
241 | - | ||
242 | -### Explicación del video | ||
243 | - | ||
244 | -Amateur Coder hizo un excelente video que cubre route management con Get! aquí esta el link: [Complete Getx Navigation](https://www.youtube.com/watch?v=RaqPIoJSTtI) | ||
245 | - | ||
246 | -## Gestión de dependencias | ||
247 | - | ||
248 | -- Nota: si está utilizando el gestor de estado de GetX, no tiene que preocuparse por esto, solo lea para obtener información, pero preste más atención a la API de bindings, que hará todo esto automáticamente por usted. | ||
249 | - | ||
250 | -¿Ya estás utilizando GetX y quieres que tu proyecto sea lo más ágil posible? GetX tiene un gestor de dependencias simple y poderoso que le permite recuperar la misma clase que su BLoC o Controller con solo una líneas de código, sin contexto de Provider, sin inheritedWidget: | ||
251 | - | ||
252 | -```dart | ||
253 | -Controller controller = Get.put(Controller()); // Rather Controller controller = Controller(); | ||
254 | -``` | ||
255 | - | ||
256 | -En lugar de crear una instancia de su clase dentro de la clase que está utilizando, la está creando dentro de la instancia GetX, que la hará disponible en toda su aplicación. Entonces puede usar su Controller (o BLoC) normalmente. | ||
257 | - | ||
258 | -```dart | ||
259 | -controller.fetchApi(); | ||
260 | -``` | ||
261 | - | ||
262 | -Imagine que ha navegado a través de numerosas rutas y necesita datos que quedaron en su controlador, necesitaría un gestor de estado combinado con Provider o Get_it, ¿correcto? No con GetX. Solo necesita pedirle a GetX que "encuentre" su controlador, no necesita dependencias adicionales: | ||
263 | - | ||
264 | -```dart | ||
265 | -Controller controller = Get.find(); | ||
266 | -//Sí, parece que es magia, Get encontrará su controlador y se lo entregará. Puede tener 1 millón de controladores instanciados, Get siempre le dará el controlador correcto. | ||
267 | -``` | ||
268 | - | ||
269 | -Y luego podrá recuperar los datos de su controlador que se obtuvieron allí: | ||
270 | - | ||
271 | -```dart | ||
272 | -Text(controller.textFromApi); | ||
273 | -``` | ||
274 | - | ||
275 | -¿Buscando lazy loading? Puede declarar todos sus controladores, y se llamará solo cuando alguien lo necesite. Puedes hacer esto con: | ||
276 | - | ||
277 | -```dart | ||
278 | -Get.lazyPut<Service>(()=> ApiMock()); | ||
279 | -/// ApiMock solo se llamará cuando alguien use Get.find<Service> por primera vez | ||
280 | -``` | ||
281 | - | ||
282 | -### Más detalles sobre la gestión de dependencias. | ||
283 | - | ||
284 | -**Vea una explicación más detallada de la Gestión de dependencias [aquí](./documentation/es_ES/dependency_management.md).** | ||
285 | - | ||
286 | -# Utilidades | ||
287 | - | ||
288 | -## Cambiar de tema | ||
289 | - | ||
290 | -No utilice ningún widget de nivel superior que GetMaterialApp para actualizarlo. Esto puede activar claves duplicadas. Mucha gente está acostumbrada al enfoque prehistórico de crear un widget "ThemeProvider" solo para cambiar el tema de su aplicación, y esto definitivamente NO es necesario con GetX. | ||
291 | - | ||
292 | -Puede crear su tema personalizado y simplemente agregarlo dentro de Get.changeTheme sin ningún boilerplate para eso: | ||
293 | - | ||
294 | -```dart | ||
295 | -Get.changeTheme(ThemeData.light()); | ||
296 | -``` | ||
297 | - | ||
298 | -Si desea crear algo así como un botón que cambia el tema con onTap, puede combinar dos APIs GetX para eso, la API que verifica si se está utilizando el tema oscuro y la API de cambio de tema, simplemente puede poner esto dentro de un onPressed: | ||
299 | - | ||
300 | -```dart | ||
301 | -Get.changeTheme(Get.isDarkMode? ThemeData.light(): ThemeData.dark()); | ||
302 | -``` | ||
303 | - | ||
304 | -Cuando el modo oscuro está activado, cambiará al tema claro, y cuando el tema claro esté activado, cambiará a oscuro. | ||
305 | - | ||
306 | -Si quieres saber en profundidad cómo cambiar el tema, puedes seguir este tutorial en Medium que incluso enseña la persistencia del tema usando GetX: | ||
307 | - | ||
308 | -- [Temas dinámicos en 3 líneas usando GetX](https://medium.com/swlh/flutter-dynamic-themes-in-3-lines-c3b375f292e3) - Tutorial de [Rod Brown](https://github.com/RodBr). | ||
309 | - | ||
310 | -## Otras API avanzadas y configuraciones manuales | ||
311 | - | ||
312 | -GetMaterialApp configura todo para usted, pero si desea configurar GetX manualmente utilizando APIs avanzadas. | ||
313 | - | ||
314 | -```dart | ||
315 | -MaterialApp( | ||
316 | - navigatorKey: Get.key, | ||
317 | - navigatorObservers: [GetObserver()], | ||
318 | -); | ||
319 | -``` | ||
320 | - | ||
321 | -También podrá usar su propio Middleware dentro de GetObserver, esto no influirá en nada. | ||
322 | - | ||
323 | -```dart | ||
324 | -MaterialApp( | ||
325 | - navigatorKey: Get.key, | ||
326 | - navigatorObservers: [GetObserver(MiddleWare.observer)], // Here | ||
327 | -); | ||
328 | -``` | ||
329 | - | ||
330 | -```dart | ||
331 | -// dar los argumentos actuales de currentScreen | ||
332 | -Get.arguments | ||
333 | - | ||
334 | -// dar argumentos de la ruta anterior | ||
335 | -Get.previousArguments | ||
336 | - | ||
337 | -// dar el nombre de la ruta anterior | ||
338 | -Get.previousRoute | ||
339 | - | ||
340 | -// dar la ruta sin procesar para acceder, por ejemplo, rawRoute.isFirst() | ||
341 | -Get.rawRoute | ||
342 | - | ||
343 | -// dar acceso a Routing API desde GetObserver | ||
344 | -Get.routing | ||
345 | - | ||
346 | -// comprobar si la cafetería está abierta | ||
347 | -Get.isSnackbarOpen | ||
348 | - | ||
349 | -// comprobar si el diálogo está abierto | ||
350 | -Get.isDialogOpen | ||
351 | - | ||
352 | -// comprobar si bottomsheet está abierto | ||
353 | -Get.isBottomSheetOpen | ||
354 | - | ||
355 | -// eliminar una ruta. | ||
356 | -Get.removeRoute() | ||
357 | - | ||
358 | -// volver repetidamente hasta que predicate devuelva verdadero. | ||
359 | -Get.until() | ||
360 | - | ||
361 | -//ir a la siguiente ruta y eliminar todas las rutas anteriores hasta que predicate devuelva verdadero. | ||
362 | -Get.offUntil() | ||
363 | - | ||
364 | -// ir a la siguiente ruta con nombre y eliminar todas las rutas anteriores hasta que predicate devuelve verdadero. | ||
365 | -Get.offNamedUntil() | ||
366 | - | ||
367 | -//Verifique en qué plataforma se ejecuta la aplicación | ||
368 | -GetPlatform.isAndroid | ||
369 | -GetPlatform.isIOS | ||
370 | -GetPlatform.isWeb | ||
371 | - | ||
372 | -// Equivalente al método: MediaQuery.of(context).size.height, pero son inmutables. | ||
373 | -Get.height | ||
374 | -Get.width | ||
375 | - | ||
376 | -// Da el contexto de la pantalla en primer plano en cualquier parte de su código. | ||
377 | -Get.context | ||
378 | - | ||
379 | -// Da el contexto de la barra de bocadillos / diálogo / hoja inferior en primer plano en cualquier parte de su código. | ||
380 | -Get.contextOverlay | ||
381 | - | ||
382 | -// Note: los siguientes métodos son extensiones de context. Desde que tu | ||
383 | -// tiene acceso al contexto en cualquier lugar de su interfaz de usuario, puede usarlo en cualquier lugar del código de la interfaz de usuario | ||
384 | - | ||
385 | -// Si necesita un cambiable height/width (como las ventanas del navegador que se pueden escalar) necesitará usar context. | ||
386 | -context.width | ||
387 | -context.height | ||
388 | - | ||
389 | - | ||
390 | - | ||
391 | -// le da el poder de definir la mitad de la pantalla ahora, un tercio y así sucesivamente. | ||
392 | -// Útil para aplicaciones receptivas. | ||
393 | -// param dividedBy (double) optional - default: 1 | ||
394 | -// param reducedBy (double) optional - default: 0 | ||
395 | -context.heightTransformer() | ||
396 | -context.widthTransformer() | ||
397 | - | ||
398 | -/// Similar a MediaQuery.of(context).size | ||
399 | -context.mediaQuerySize() | ||
400 | - | ||
401 | -/// similar a MediaQuery.of(context).padding | ||
402 | -context.mediaQueryPadding() | ||
403 | - | ||
404 | -/// similar a MediaQuery.of(context).viewPadding | ||
405 | -context.mediaQueryViewPadding() | ||
406 | - | ||
407 | -/// similar a MediaQuery.of(context).viewInsets; | ||
408 | -context.mediaQueryViewInsets() | ||
409 | - | ||
410 | -/// similar a MediaQuery.of(context).orientation; | ||
411 | -context.orientation() | ||
412 | - | ||
413 | -/// comprobar si el dispositivo esta en landscape mode | ||
414 | -context.isLandscape() | ||
415 | - | ||
416 | -/// comprobar si el dispositivo esta en portrait mode | ||
417 | -context.isPortrait() | ||
418 | - | ||
419 | -/// similar a MediaQuery.of(context).devicePixelRatio; | ||
420 | -context.devicePixelRatio() | ||
421 | - | ||
422 | -/// similar a MediaQuery.of(context).textScaleFactor; | ||
423 | -context.textScaleFactor() | ||
424 | - | ||
425 | -/// obtener el lado más corto de la pantalla | ||
426 | -context.mediaQueryShortestSide() | ||
427 | - | ||
428 | -/// Verdadero si el ancho es mayor que 800 | ||
429 | -context.showNavbar() | ||
430 | - | ||
431 | -/// Verdadero si el lado más corto es menor que 600p | ||
432 | -context.isPhone() | ||
433 | - | ||
434 | -/// Verdadero si el lado más corto es más grande que 600p | ||
435 | -context.isSmallTablet() | ||
436 | - | ||
437 | -/// Verdadero si el lado más corto es mayor que 720p | ||
438 | -context.isLargeTablet() | ||
439 | - | ||
440 | -/// Verdadero si el dispositivo actual es una tableta | ||
441 | -context.isTablet() | ||
442 | -``` | ||
443 | - | ||
444 | -### Configuraciones globales opcionales | ||
445 | - | ||
446 | -Puede crear configuraciones globales para GetX. Simplemente agregue Get.config a su código antes de insertar cualquier ruta o hágalo directamente en su GetMaterialApp | ||
447 | - | ||
448 | -```dart | ||
449 | -GetMaterialApp( | ||
450 | - enableLog: true, | ||
451 | - defaultTransition: Transition.fade, | ||
452 | - opaqueRoute: Get.isOpaqueRouteDefault, | ||
453 | - popGesture: Get.isPopGestureEnable, | ||
454 | - transitionDuration: Get.defaultDurationTransition, | ||
455 | - defaultGlobalState: Get.defaultGlobalState, | ||
456 | -); | ||
457 | - | ||
458 | -Get.config( | ||
459 | - enableLog = true, | ||
460 | - defaultPopGesture = true, | ||
461 | - defaultTransition = Transitions.cupertino | ||
462 | -) | ||
463 | -``` | ||
464 | - | ||
465 | -Opcionalmente, puede redirigir todos los mensajes de registro de Get. Si desea utilizar su propio paquete de registro favorito y desea capturar los registros allí. | ||
466 | - | ||
467 | -```dart | ||
468 | -GetMaterialApp( | ||
469 | - enableLog: true, | ||
470 | - logWriterCallback: localLogWriter, | ||
471 | -); | ||
472 | - | ||
473 | -void localLogWriter(String text, {bool isError = false}) { | ||
474 | - // pase el mensaje a su paquete de registro favorito aquí | ||
475 | - //Nota: incluso si los mensajes de registro están desactivados | ||
476 | - // con el comando "enableLog: false", los mensajes seguirán pasando por aquí | ||
477 | - // Debe verificar esta configuración manualmente aquí si desea respetarla | ||
478 | -} | ||
479 | - | ||
480 | -``` | ||
481 | - | ||
482 | -## Video explanation of Other GetX Features | ||
483 | - | ||
484 | -Amateur Coder hizo un video asombroso sobre utilidades, almacenamiento, enlaces y otras características! Link: [GetX Other Features](https://youtu.be/ttQtlX_Q0eU) | ||
485 | - | ||
486 | -# Rompiendo cambios desde 2.0 | ||
487 | - | ||
488 | -1- Rx types: | ||
489 | - | ||
490 | -Antes: StringX ahora: RxString | ||
491 | - | ||
492 | -Antes: IntX ahora: RxInt | ||
493 | - | ||
494 | -Antes: MapX ahora: RxMap | ||
495 | - | ||
496 | -Antes: ListX ahora: RxList | ||
497 | - | ||
498 | -Antes: NumX ahora: RxNum | ||
499 | - | ||
500 | -Antes: RxDouble ahora: RxDouble | ||
501 | - | ||
502 | -RxController y GetBuilder ahora se han fusionado, ya no necesita memorizar qué controlador desea usar, solo use GetXController, funcionará para gestión de estádo simple y también para reactivo. | ||
503 | - | ||
504 | -2- Rutas Nombradas | ||
505 | - | ||
506 | -Antes: | ||
507 | - | ||
508 | -```dart | ||
509 | -GetMaterialApp( | ||
510 | - namedRoutes: { | ||
511 | - '/': GetRoute(page: Home()), | ||
512 | - } | ||
513 | -) | ||
514 | -``` | ||
515 | - | ||
516 | -Ahora: | ||
517 | - | ||
518 | -```dart | ||
519 | -GetMaterialApp( | ||
520 | - getPages: [ | ||
521 | - GetPage(name: '/', page: () => Home()), | ||
522 | - ] | ||
523 | -) | ||
524 | -``` | ||
525 | - | ||
526 | -¿Por qué este cambio? | ||
527 | - | ||
528 | -A menudo, puede ser necesario decidir qué página se mostrará desde un parámetro o un token de inicio de sesión, el enfoque anterior era inflexible, ya que no permitía esto. | ||
529 | - | ||
530 | -Insertar la página en una función ha reducido significativamente el consumo de RAM, ya que las rutas no se asignarán en la memoria desde que se inició la aplicación, y también permitió hacer este tipo de enfoque: | ||
531 | - | ||
532 | -```dart | ||
533 | -GetStorage box = GetStorage(); | ||
534 | - | ||
535 | -GetMaterialApp( | ||
536 | - getPages: [ | ||
537 | - GetPage(name: '/', page:(){ | ||
538 | - return box.hasData('token') ? Home() : Login(); | ||
539 | - }) | ||
540 | - ] | ||
541 | -) | ||
542 | -``` | ||
543 | - | ||
544 | -# ¿Por qué Getx? | ||
545 | - | ||
546 | -1- Después de una actualización de Flutter, muchos paquetes suelen romperse. A veces se producen errores de compilación, errores de los que aún no hay respuestas y el desarrollador necesita saber el origen del error, poder rastrear, y solo entonces intentar abrir un issue en el repositorio correspondiente, para finalmente ver su problema resuelto. Getx centraliza los principales recursos para el desarrollo (gestión de estado, dependencia y rutas), lo que le permite agregar un único paquete a su pubspec y comenzar a trabajar. Después de una actualización de Flutter, lo único que debe hacer es actualizar la dependencia Get y ponerse a trabajar. Get también resuelve problemas de compatibilidad. ¿Cuántas veces una versión de un paquete no es compatible con la versión de otro, porque una usa una dependencia en una versión y la otra en otra? Tampoco es una preocupación usando Get, ya que todo estará en el mismo paquete y será totalmente compatible. | ||
547 | - | ||
548 | -2- Flutter es fácil, Flutter es increíble, pero todavía tiene algo repetitivo que puede ser no deseado para la mayoría de los desarrolladores, como `Navigator.of(context).push (context, builder [...]`. Get simplifica el desarrollo. En lugar de escribir 8 líneas de código para simplemente llamar a una ruta, simplemente puede hacerlo: `Get.to(Home())` y listo, irá a la página siguiente. Algo doloroso de hacer con Flutter actualmente, mientras que con GetX es estúpidamente simple. Gestionar estados en Flutter y dependencias también es algo que genera mucho debate, ya que hay cientos de patrones en el pub. Pero no hay nada tan fácil como agregar un ".obs" al final de su variable, y colocar su widget dentro de un Obx, y eso es todo, todas las actualizaciones de esa variable se actualizarán automáticamente en la pantalla. | ||
549 | - | ||
550 | -3- Facilidad sin preocuparse por el rendimiento. El rendimiento de Flutter ya es sorprendente, pero imagine que usa un gestor de estado y un localizador para distribuir sus clases de bloc/stores/controllers/ etc. Tendrá que llamar manualmente a la exclusión de esa dependencia cuando no la necesite. Pero, ¿alguna vez pensó en simplemente usar el controlador, y cuando ya no sea necesario, simplemente se elimine de la memoria? Eso es lo que hace GetX. Con SmartManagement, todo lo que no se está utilizando se elimina de la memoria, y no debería tener que preocuparse por nada más que la programación. Se le garantiza el consumo mínimo de recursos, sin siquiera haber creado una lógica para esto. | ||
551 | - | ||
552 | -4- Desacoplamiento real. Es posible que haya escuchado la idea de "separar la vista de la lógica de negocio". Esta no es una peculiaridad de BLoC, MVC, MVVM, cualquier otro estándar en el mercado tiene este concepto. Sin embargo, a menudo se puede mitigar en Flutter debido al uso del contexto. | ||
553 | -Si necesita contexto para encontrar un InheritedWidget, lo necesita en la vista o pasado por parámetro. En particular, encuentro esta solución muy fea, y para trabajar en equipo siempre tendremos una dependencia de la lógica de negocios de la vista. Getx no es ortodoxo con el enfoque estándar, y aunque no prohíbe completamente el uso de StatefulWidgets, InitState, etc., siempre tiene un enfoque similar que puede ser más limpio. Los controladores tienen ciclos de vida, y cuando necesita hacer una solicitud API REST, por ejemplo, no depende de nada en la vista. Puede usar onInit para iniciar la llamada http, y cuando lleguen los datos, se rellenarán las variables. Como GetX es completamente reactivo (realmente, y funciona bajo streams), una vez que se llenan los elementos, todos los widgets que usan esa variable se actualizarán automáticamente en la vista. Esto permite que las personas con experiencia en IU trabajen solo con widgets y no tengan que enviar nada a la lógica de negocios que no sean eventos de usuario (como hacer clic en un botón), mientras que las personas que trabajan con lógica de negocios podrán crearla y probarla por separado. | ||
554 | - | ||
555 | -Esta librería siempre se actualizará e implementará nuevas características. Siéntase libre de ofrecer PRs y contribuir a ellas. |
getx/README.md
deleted
100644 → 0
1 | - | ||
2 | - | ||
3 | -_Languages: English (this file), [Brazilian Portuguese](README.pt-br.md), [Spanish](README-es.md),[Polish](README.pl.md)._ | ||
4 | - | ||
5 | -[](https://pub.dev/packages/get) | ||
6 | - | ||
7 | -[](https://pub.dev/packages/effective_dart) | ||
8 | -[](https://discord.com/invite/9Hpt99N) | ||
9 | -[](https://communityinviter.com/apps/getxworkspace/getx) | ||
10 | -[](https://t.me/joinchat/PhdbJRmsZNpAqSLJL6bH7g) | ||
11 | -<a href="https://github.com/Solido/awesome-flutter"> | ||
12 | -<img alt="Awesome Flutter" src="https://img.shields.io/badge/Awesome-Flutter-blue.svg?longCache=true&style=flat-square" /> | ||
13 | -</a> | ||
14 | -<a href="https://www.buymeacoffee.com/jonataslaw" target="_blank"><img src="https://i.imgur.com/aV6DDA7.png" alt="Buy Me A Coffee" style="height: 41px !important;width: 174px !important; box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;" > </a> | ||
15 | - | ||
16 | - | ||
17 | - | ||
18 | -- [About Get](#about-get) | ||
19 | -- [Installing](#installing) | ||
20 | -- [Counter App with GetX](#counter-app-with-getx) | ||
21 | -- [The Three pillars](#the-three-pillars) | ||
22 | - - [State management](#state-management) | ||
23 | - - [Reactive State Manager](#reactive-state-manager) | ||
24 | - - [More details about state management](#more-details-about-state-management) | ||
25 | - - [Route management](#route-management) | ||
26 | - - [More details about route management](#more-details-about-route-management) | ||
27 | - - [Dependency management](#dependency-management) | ||
28 | - - [More details about dependency management](#more-details-about-dependency-management) | ||
29 | -- [Utils](#utils) | ||
30 | - - [Internationalization](#internationalization) | ||
31 | - - [Translations](#translations) | ||
32 | - - [Using translations](#using-translations) | ||
33 | - - [Locales](#locales) | ||
34 | - - [Change locale](#change-locale) | ||
35 | - - [System locale](#system-locale) | ||
36 | - - [Change Theme](#change-theme) | ||
37 | - - [Other Advanced APIs](#other-advanced-apis) | ||
38 | - - [Optional Global Settings and Manual configurations](#optional-global-settings-and-manual-configurations) | ||
39 | - - [Local State Widgets](#local-state-widgets) | ||
40 | - - [ValueBuilder](#valuebuilder) | ||
41 | - - [ObxValue](#obxvalue) | ||
42 | - - [Useful tips](#useful-tips) | ||
43 | - - [GetView](#getview) | ||
44 | - - [GetWidget](#getwidget) | ||
45 | - - [GetxService](#getxservice) | ||
46 | -- [Breaking changes from 2.0](#breaking-changes-from-20) | ||
47 | -- [Why Getx?](#why-getx) | ||
48 | -- [Community](#community) | ||
49 | - - [Community channels](#community-channels) | ||
50 | - - [How to contribute](#how-to-contribute) | ||
51 | - - [Articles and videos](#articles-and-videos) | ||
52 | - | ||
53 | -# About Get | ||
54 | - | ||
55 | -- GetX is an extra-light and powerful solution for Flutter. It combines high performance state management, intelligent dependency injection, and route management in a quick and practical way. | ||
56 | - | ||
57 | -- GetX has 3 basic principles, this means that this is the priority for all resources in the library | ||
58 | - | ||
59 | - - **PERFORMANCE:** GetX is focused on performance and minimum consumption of resources. Benchmarks are almost always not important in the real world, but if you want, there is a consumption indicator here([benchmarks](https://github.com/jonataslaw/benchmarks)), where GetX does better than other state management approaches, for example. The difference is not large, but it shows our concern not to waste its resources. | ||
60 | - - **PRODUCTIVITY:** GetX uses an easy and pleasant syntax. No matter what you want to do, there is always an easier way with Getx. It will save hours of development, and will extract the maximum performance that your application can deliver | ||
61 | - - **ORGANIZATION:** GetX allows the total decoupling of the View, presentation logic, business logic, dependency injection, and navigation. You do not need context to navigate between routes, so you are not dependent on the widget tree (visualization) for this. You don't need context to access your controllers / blocks through an inheritedWidget, so you completely decouple your presentation logic and business logic from your visualization layer. You do not need to inject your Controllers/Models/Blocs classes into your widget tree through multiproviders, for this GetX uses its own dependency injection feature, decoupling the DI from its view completely. | ||
62 | - With GetX you know where to find each feature of your application, having clean code by default. This in addition to facilitating maintenance, makes the sharing of modules, something that until then in Flutter was unthinkable, something totally possible. | ||
63 | - BLoC was a starting point for organizing code in Flutter, it separates business logic from visualization. Getx is a natural evolution of this, not only separating the business logic, but the presentation logic. Bonus injection of dependencies and routes are also decoupled, and the data layer is out of it all. You know where everything is, and all of this in an easier way than building a hello world. | ||
64 | - GetX is the easiest, most practical and scalable way to build high-performance applications with the Flutter SDK, with a large ecosystem around it that works perfectly together, being easy for beginners, and accurate for experts. It is secure, stable, up-to-date, and offers a huge range of APIs build-in that are not present on default Flutter SDK. | ||
65 | - | ||
66 | -- GetX is not a bloated. It has a multitude of features that allow you to start programming without worrying about anything, but each of these features are in separate containers, and are only started after use. If you only use State Management, only State Management will be compiled. If you only use routes, nothing from the state management will be compiled. You can compile the benchmark repository, and you will see that using only Get state management, the application compiled with Get has become smaller than all other applications that have only the state management of other packages, because nothing that is not used will be compiled into your code, and each GetX solution was designed to be extra lightweight. The merit here also comes from Flutter's tree shaking which is incredible, and manages to eliminate unused resources like no other framework does. | ||
67 | - | ||
68 | -- Getx has a huge ecosystem, capable of running with the same code on Android, iOS, Web, Mac, Linux, Windows, and on your server. | ||
69 | -**It is possible to fully reuse your code made on the frontend on your backend with [Get Server](https://github.com/jonataslaw/get_server)**. | ||
70 | - | ||
71 | -**In addition, the entire development process can be completely automated, both on the server and on the front end with [Get CLI](https://github.com/jonataslaw/get_cli)**. | ||
72 | - | ||
73 | -**In addition, to further increase your productivity, we have the | ||
74 | -[extension to VSCode](https://marketplace.visualstudio.com/items?itemName=get-snippets.get-snippets) and the [extension to Android Studio/Intellij](https://plugins.jetbrains.com/plugin/14975-getx-snippets)** | ||
75 | - | ||
76 | -# Installing | ||
77 | - | ||
78 | -Add Get to your pubspec.yaml file: | ||
79 | - | ||
80 | -```yaml | ||
81 | -dependencies: | ||
82 | - get: | ||
83 | -``` | ||
84 | - | ||
85 | -Import get in files that it will be used: | ||
86 | - | ||
87 | -```dart | ||
88 | -import 'package:get/get.dart'; | ||
89 | -``` | ||
90 | - | ||
91 | -# Counter App with GetX | ||
92 | - | ||
93 | -The "counter" project created by default on new project on Flutter has over 100 lines (with comments). To show the power of Get, I will demonstrate how to make a "counter" changing the state with each click, switching between pages and sharing the state between screens, all in an organized way, separating the business logic from the view, in ONLY 26 LINES CODE INCLUDING COMMENTS. | ||
94 | - | ||
95 | -- Step 1: | ||
96 | - Add "Get" before your MaterialApp, turning it into GetMaterialApp | ||
97 | - | ||
98 | -```dart | ||
99 | -void main() => runApp(GetMaterialApp(home: Home())); | ||
100 | -``` | ||
101 | - | ||
102 | -- Note: this does not modify the MaterialApp of the Flutter, GetMaterialApp is not a modified MaterialApp, it is just a pre-configured Widget, which has the default MaterialApp as a child. You can configure this manually, but it is definitely not necessary. GetMaterialApp will create routes, inject them, inject translations, inject everything you need for route navigation. If you use Get only for state management or dependency management, it is not necessary to use GetMaterialApp. GetMaterialApp is necessary for routes, snackbars, internationalization, bottomSheets, dialogs, and high-level apis related to routes and absence of context. | ||
103 | -- Note²: This step in only necessary if you gonna use route management (`Get.to()`, `Get.back()` and so on). If you not gonna use it then it is not necessary to do step 1 | ||
104 | - | ||
105 | -- Step 2: | ||
106 | - Create your business logic class and place all variables, methods and controllers inside it. | ||
107 | - You can make any variable observable using a simple ".obs". | ||
108 | - | ||
109 | -```dart | ||
110 | -class Controller extends GetxController{ | ||
111 | - var count = 0.obs; | ||
112 | - increment() => count++; | ||
113 | -} | ||
114 | -``` | ||
115 | - | ||
116 | -- Step 3: | ||
117 | - Create your View, use StatelessWidget and save some RAM, with Get you may no longer need to use StatefulWidget. | ||
118 | - | ||
119 | -```dart | ||
120 | -class Home extends StatelessWidget { | ||
121 | - | ||
122 | - // Instantiate your class using Get.put() to make it available for all "child" routes there. | ||
123 | - final Controller c = Get.put(Controller()); | ||
124 | - | ||
125 | - @override | ||
126 | - Widget build(context) => Scaffold( | ||
127 | - // Use Obx(()=> to update Text() whenever count is changed. | ||
128 | - appBar: AppBar(title: Obx(() => Text("Clicks: ${c.count}"))), | ||
129 | - | ||
130 | - // Replace the 8 lines Navigator.push by a simple Get.to(). You don't need context | ||
131 | - body: Center(child: RaisedButton( | ||
132 | - child: Text("Go to Other"), onPressed: () => Get.to(Other()))), | ||
133 | - floatingActionButton: | ||
134 | - FloatingActionButton(child: Icon(Icons.add), onPressed: c.increment)); | ||
135 | -} | ||
136 | - | ||
137 | -class Other extends StatelessWidget { | ||
138 | - // You can ask Get to find a Controller that is being used by another page and redirect you to it. | ||
139 | - final Controller c = Get.find(); | ||
140 | - | ||
141 | - @override | ||
142 | - Widget build(context){ | ||
143 | - // Access the updated count variable | ||
144 | - return Scaffold(body: Center(child: Text("${c.count}"))); | ||
145 | - } | ||
146 | -} | ||
147 | -``` | ||
148 | - | ||
149 | -Result: | ||
150 | - | ||
151 | - | ||
152 | - | ||
153 | -This is a simple project but it already makes clear how powerful Get is. As your project grows, this difference will become more significant. | ||
154 | - | ||
155 | -Get was designed to work with teams, but it makes the job of an individual developer simple. | ||
156 | - | ||
157 | -Improve your deadlines, deliver everything on time without losing performance. Get is not for everyone, but if you identified with that phrase, Get is for you! | ||
158 | - | ||
159 | -# The Three pillars | ||
160 | - | ||
161 | -## State management | ||
162 | - | ||
163 | -There are currently several state managers for Flutter. However, most of them involve using ChangeNotifier to update widgets and this is a bad and very bad approach to performance of medium or large applications. You can check in the official Flutter documentation that [ChangeNotifier should be used with 1 or a maximum of 2 listeners](https://api.flutter.dev/flutter/foundation/ChangeNotifier-class.html), making it practically unusable for any application medium or large. | ||
164 | - | ||
165 | -Get isn't better or worse than any other state manager, but that you should analyze these points as well as the points below to choose between using Get in pure form (Vanilla), or using it in conjunction with another state manager. | ||
166 | - | ||
167 | -Definitely, Get is not the enemy of any other state manager, because Get is a microframework, not just a state manager, and can be used either alone or in conjunction with them. | ||
168 | - | ||
169 | -Get has two different state managers: the simple state manager (we'll call it GetBuilder) and the reactive state manager (who has the package name, GetX) | ||
170 | - | ||
171 | -### Reactive State Manager | ||
172 | - | ||
173 | -Reactive programming can alienate many people because it is said to be complicated. GetX turns reactive programming into something quite simple: | ||
174 | - | ||
175 | -- You won't need to create StreamControllers. | ||
176 | -- You won't need to create a StreamBuilder for each variable | ||
177 | -- You will not need to create a class for each state. | ||
178 | -- You will not need to create a get for an initial value. | ||
179 | - | ||
180 | -Reactive programming with Get is as easy as using setState. | ||
181 | - | ||
182 | -Let's imagine that you have a name variable and want that every time you change it, all widgets that use it are automatically changed. | ||
183 | - | ||
184 | -This is your count variable: | ||
185 | - | ||
186 | -```dart | ||
187 | -var name = 'Jonatas Borges'; | ||
188 | -``` | ||
189 | - | ||
190 | -To make it observable, you just need to add ".obs" to the end of it: | ||
191 | - | ||
192 | -```dart | ||
193 | -var name = 'Jonatas Borges'.obs; | ||
194 | -``` | ||
195 | - | ||
196 | -And in the UI, when you want to show that value and update the screen whenever tha values changes, simply do this: | ||
197 | - | ||
198 | -```dart | ||
199 | -Obx(() => Text("${controller.name}")); | ||
200 | -``` | ||
201 | - | ||
202 | -That's all. It's _that_ simple. | ||
203 | - | ||
204 | -### More details about state management | ||
205 | - | ||
206 | -**See an more in-depth explanation of state management [here](./documentation/en_US/state_management.md). There you will see more examples and also the difference between the simple stage manager and the reactive state manager** | ||
207 | - | ||
208 | -You will get a good idea of GetX power. | ||
209 | - | ||
210 | -## Route management | ||
211 | - | ||
212 | -If you are going to use routes/snackbars/dialogs/bottomsheets without context, GetX is excellent for you too, just see it: | ||
213 | - | ||
214 | -Add "Get" before your MaterialApp, turning it into GetMaterialApp | ||
215 | - | ||
216 | -```dart | ||
217 | -GetMaterialApp( // Before: MaterialApp( | ||
218 | - home: MyHome(), | ||
219 | -) | ||
220 | -``` | ||
221 | - | ||
222 | -Navigate to new screen: | ||
223 | - | ||
224 | -```dart | ||
225 | - | ||
226 | -Get.to(NextScreen()); | ||
227 | -``` | ||
228 | - | ||
229 | -Navigate to new screen with name. See more details on named routes [here](./documentation/en_US/route_management.md#navigation-with-named-routes) | ||
230 | - | ||
231 | -```dart | ||
232 | - | ||
233 | -Get.toNamed('/details'); | ||
234 | -``` | ||
235 | - | ||
236 | -To close snackbars, dialogs, bottomsheets, or anything you would normally close with Navigator.pop(context); | ||
237 | - | ||
238 | -```dart | ||
239 | -Get.back(); | ||
240 | -``` | ||
241 | - | ||
242 | -To go to the next screen and no option to go back to the previous screen (for use in SplashScreens, login screens and etc.) | ||
243 | - | ||
244 | -```dart | ||
245 | -Get.off(NextScreen()); | ||
246 | -``` | ||
247 | - | ||
248 | -To go to the next screen and cancel all previous routes (useful in shopping carts, polls, and tests) | ||
249 | - | ||
250 | -```dart | ||
251 | -Get.offAll(NextScreen()); | ||
252 | -``` | ||
253 | - | ||
254 | -Noticed that you didn't had to use context to do any of these things? That's one of the biggest advantages of using Get route management. With this, you can execute all these methods from within your controller class, without worries. | ||
255 | - | ||
256 | -### More details about route management | ||
257 | - | ||
258 | -**Get work with named routes and also offer a lower level control over your routes! There is a in-depth documentation [here](./documentation/en_US/route_management.md)** | ||
259 | - | ||
260 | -## Dependency management | ||
261 | - | ||
262 | -Get has a simple and powerful dependency manager that allows you to retrieve the same class as your Bloc or Controller with just 1 lines of code, no Provider context, no inheritedWidget: | ||
263 | - | ||
264 | -```dart | ||
265 | -Controller controller = Get.put(Controller()); // Rather Controller controller = Controller(); | ||
266 | -``` | ||
267 | - | ||
268 | -- Note: If you are using Get's State Manager, pay more attention to the bindings api, which will make easier to connect your view to your controller. | ||
269 | - | ||
270 | -Instead of instantiating your class within the class you are using, you are instantiating it within the Get instance, which will make it available throughout your App. | ||
271 | -So you can use your controller (or class Bloc) normally | ||
272 | - | ||
273 | -**Tip:** Get dependency management is decloupled from other parts of the package, so if for example your app is already using a state manager (any one, it doesn't matter), you don't need to rewrite it all, you can use this dependency injection with no problems at all | ||
274 | - | ||
275 | -```dart | ||
276 | -controller.fetchApi(); | ||
277 | -``` | ||
278 | - | ||
279 | -Imagine that you have navigated through numerous routes, and you need a data that was left behind in your controller, you would need a state manager combined with the Provider or Get_it, correct? Not with Get. You just need to ask Get to "find" for your controller, you don't need any additional dependencies: | ||
280 | - | ||
281 | -```dart | ||
282 | -Controller controller = Get.find(); | ||
283 | -//Yes, it looks like Magic, Get will find your controller, and will deliver it to you. You can have 1 million controllers instantiated, Get will always give you the right controller. | ||
284 | -``` | ||
285 | - | ||
286 | -And then you will be able to recover your controller data that was obtained back there: | ||
287 | - | ||
288 | -```dart | ||
289 | -Text(controller.textFromApi); | ||
290 | -``` | ||
291 | - | ||
292 | -### More details about dependency management | ||
293 | - | ||
294 | -**See a more in-depth explanation of dependency management [here](./documentation/en_US/dependency_management.md)** | ||
295 | - | ||
296 | -# Utils | ||
297 | - | ||
298 | -## Internationalization | ||
299 | - | ||
300 | -### Translations | ||
301 | - | ||
302 | -Translations are kept as a simple key-value dictionary map. | ||
303 | -To add custom translations, create a class and extend `Translations`. | ||
304 | - | ||
305 | -```dart | ||
306 | -import 'package:get/get.dart'; | ||
307 | - | ||
308 | -class Messages extends Translations { | ||
309 | - @override | ||
310 | - Map<String, Map<String, String>> get keys => { | ||
311 | - 'en_US': { | ||
312 | - 'hello': 'Hello World', | ||
313 | - }, | ||
314 | - 'de_DE': { | ||
315 | - 'hello': 'Hallo Welt', | ||
316 | - } | ||
317 | - }; | ||
318 | -} | ||
319 | -``` | ||
320 | - | ||
321 | -#### Using translations | ||
322 | - | ||
323 | -Just append `.tr` to the specified key and it will be translated, using the current value of `Get.locale` and `Get.fallbackLocale`. | ||
324 | - | ||
325 | -```dart | ||
326 | -Text('title'.tr); | ||
327 | -``` | ||
328 | - | ||
329 | -### Locales | ||
330 | - | ||
331 | -Pass parameters to `GetMaterialApp` to define the locale and translations. | ||
332 | - | ||
333 | -```dart | ||
334 | -return GetMaterialApp( | ||
335 | - translations: Messages(), // your translations | ||
336 | - locale: Locale('en', 'US'), // translations will be displayed in that locale | ||
337 | - fallbackLocale: Locale('en', 'UK'), // specify the fallback locale in case an invalid locale is selected. | ||
338 | -); | ||
339 | -``` | ||
340 | - | ||
341 | -#### Change locale | ||
342 | - | ||
343 | -Call `Get.updateLocale(locale)` to update the locale. Translations then automatically use the new locale. | ||
344 | - | ||
345 | -```dart | ||
346 | -var locale = Locale('en', 'US'); | ||
347 | -Get.updateLocale(locale); | ||
348 | -``` | ||
349 | - | ||
350 | -#### System locale | ||
351 | - | ||
352 | -To read the system locale, you could use `window.locale`. | ||
353 | - | ||
354 | -```dart | ||
355 | -import 'dart:ui' as ui; | ||
356 | - | ||
357 | -return GetMaterialApp( | ||
358 | - locale: ui.window.locale, | ||
359 | -); | ||
360 | -``` | ||
361 | - | ||
362 | -## Change Theme | ||
363 | - | ||
364 | -Please do not use any higher level widget than `GetMaterialApp` in order to update it. This can trigger duplicate keys. A lot of people are used to the prehistoric approach of creating a "ThemeProvider" widget just to change the theme of your app, and this is definitely NOT necessary with **GetX™**. | ||
365 | - | ||
366 | -You can create your custom theme and simply add it within `Get.changeTheme` without any boilerplate for that: | ||
367 | - | ||
368 | -```dart | ||
369 | -Get.changeTheme(ThemeData.light()); | ||
370 | -``` | ||
371 | - | ||
372 | -If you want to create something like a button that changes the Theme in `onTap`, you can combine two **GetX™** APIs for that: | ||
373 | - | ||
374 | -- The api that checks if the dark `Theme` is being used. | ||
375 | -- And the `Theme` Change API, you can just put this within an `onPressed`: | ||
376 | - | ||
377 | -```dart | ||
378 | -Get.changeTheme(Get.isDarkMode? ThemeData.light(): ThemeData.dark()); | ||
379 | -``` | ||
380 | - | ||
381 | -When `.darkmode` is activated, it will switch to the _light theme_, and when the _light theme_ becomes active, it will change to _dark theme_. | ||
382 | - | ||
383 | -## Other Advanced APIs | ||
384 | - | ||
385 | -```dart | ||
386 | -// give the current args from currentScreen | ||
387 | -Get.arguments | ||
388 | - | ||
389 | -// give arguments of previous route | ||
390 | -Get.previousArguments | ||
391 | - | ||
392 | -// give name of previous route | ||
393 | -Get.previousRoute | ||
394 | - | ||
395 | -// give the raw route to access for example, rawRoute.isFirst() | ||
396 | -Get.rawRoute | ||
397 | - | ||
398 | -// give access to Rounting API from GetObserver | ||
399 | -Get.routing | ||
400 | - | ||
401 | -// check if snackbar is open | ||
402 | -Get.isSnackbarOpen | ||
403 | - | ||
404 | -// check if dialog is open | ||
405 | -Get.isDialogOpen | ||
406 | - | ||
407 | -// check if bottomsheet is open | ||
408 | -Get.isBottomSheetOpen | ||
409 | - | ||
410 | -// remove one route. | ||
411 | -Get.removeRoute() | ||
412 | - | ||
413 | -// back repeatedly until the predicate returns true. | ||
414 | -Get.until() | ||
415 | - | ||
416 | -// go to next route and remove all the previous routes until the predicate returns true. | ||
417 | -Get.offUntil() | ||
418 | - | ||
419 | -// go to next named route and remove all the previous routes until the predicate returns true. | ||
420 | -Get.offNamedUntil() | ||
421 | - | ||
422 | -//Check in what platform the app is running | ||
423 | -GetPlatform.isAndroid | ||
424 | -GetPlatform.isIOS | ||
425 | -GetPlatform.isMacOS | ||
426 | -GetPlatform.isWindows | ||
427 | -GetPlatform.isLinux | ||
428 | -GetPlatform.isFuchsia | ||
429 | - | ||
430 | -//Check the device type | ||
431 | -GetPlatform.isMobile | ||
432 | -GetPlatform.isDesktop | ||
433 | -//All platforms are supported independently in web! | ||
434 | -//You can tell if you are running inside a browser | ||
435 | -//on Windows, iOS, OSX, Android, etc. | ||
436 | -GetPlatform.isWeb | ||
437 | - | ||
438 | - | ||
439 | -// Equivalent to : MediaQuery.of(context).size.height, | ||
440 | -// but immutable. | ||
441 | -Get.height | ||
442 | -Get.width | ||
443 | - | ||
444 | -// Gives the current context of the Navigator. | ||
445 | -Get.context | ||
446 | - | ||
447 | -// Gives the context of the snackbar/dialog/bottomsheet in the foreground, anywhere in your code. | ||
448 | -Get.contextOverlay | ||
449 | - | ||
450 | -// Note: the following methods are extensions on context. Since you | ||
451 | -// have access to context in any place of your UI, you can use it anywhere in the UI code | ||
452 | - | ||
453 | -// If you need a changeable height/width (like Desktop or browser windows that can be scaled) you will need to use context. | ||
454 | -context.width | ||
455 | -context.height | ||
456 | - | ||
457 | -// Gives you the power to define half the screen, a third of it and so on. | ||
458 | -// Useful for responsive applications. | ||
459 | -// param dividedBy (double) optional - default: 1 | ||
460 | -// param reducedBy (double) optional - default: 0 | ||
461 | -context.heightTransformer() | ||
462 | -context.widthTransformer() | ||
463 | - | ||
464 | -/// Similar to MediaQuery.of(context).size | ||
465 | -context.mediaQuerySize() | ||
466 | - | ||
467 | -/// Similar to MediaQuery.of(context).padding | ||
468 | -context.mediaQueryPadding() | ||
469 | - | ||
470 | -/// Similar to MediaQuery.of(context).viewPadding | ||
471 | -context.mediaQueryViewPadding() | ||
472 | - | ||
473 | -/// Similar to MediaQuery.of(context).viewInsets; | ||
474 | -context.mediaQueryViewInsets() | ||
475 | - | ||
476 | -/// Similar to MediaQuery.of(context).orientation; | ||
477 | -context.orientation() | ||
478 | - | ||
479 | -/// Check if device is on landscape mode | ||
480 | -context.isLandscape() | ||
481 | - | ||
482 | -/// Check if device is on portrait mode | ||
483 | -context.isPortrait() | ||
484 | - | ||
485 | -/// Similar to MediaQuery.of(context).devicePixelRatio; | ||
486 | -context.devicePixelRatio() | ||
487 | - | ||
488 | -/// Similar to MediaQuery.of(context).textScaleFactor; | ||
489 | -context.textScaleFactor() | ||
490 | - | ||
491 | -/// Get the shortestSide from screen | ||
492 | -context.mediaQueryShortestSide() | ||
493 | - | ||
494 | -/// True if width be larger than 800 | ||
495 | -context.showNavbar() | ||
496 | - | ||
497 | -/// True if the shortestSide is smaller than 600p | ||
498 | -context.isPhone() | ||
499 | - | ||
500 | -/// True if the shortestSide is largest than 600p | ||
501 | -context.isSmallTablet() | ||
502 | - | ||
503 | -/// True if the shortestSide is largest than 720p | ||
504 | -context.isLargeTablet() | ||
505 | - | ||
506 | -/// True if the current device is Tablet | ||
507 | -context.isTablet() | ||
508 | - | ||
509 | -/// Returns a value<T> according to the screen size | ||
510 | -/// can give value for: | ||
511 | -/// watch: if the shortestSide is smaller than 300 | ||
512 | -/// mobile: if the shortestSide is smaller than 600 | ||
513 | -/// tablet: if the shortestSide is smaller than 1200 | ||
514 | -/// desktop: if width is largest than 1200 | ||
515 | -context.responsiveValue<T>() | ||
516 | -``` | ||
517 | - | ||
518 | -### Optional Global Settings and Manual configurations | ||
519 | - | ||
520 | -GetMaterialApp configures everything for you, but if you want to configure Get manually. | ||
521 | - | ||
522 | -```dart | ||
523 | -MaterialApp( | ||
524 | - navigatorKey: Get.key, | ||
525 | - navigatorObservers: [GetObserver()], | ||
526 | -); | ||
527 | -``` | ||
528 | - | ||
529 | -You will also be able to use your own Middleware within `GetObserver`, this will not influence anything. | ||
530 | - | ||
531 | -```dart | ||
532 | -MaterialApp( | ||
533 | - navigatorKey: Get.key, | ||
534 | - navigatorObservers: [ | ||
535 | - GetObserver(MiddleWare.observer) // Here | ||
536 | - ], | ||
537 | -); | ||
538 | -``` | ||
539 | - | ||
540 | -You can create _Global Settings_ for `Get`. Just add `Get.config` to your code before pushing any route. | ||
541 | -Or do it directly in your `GetMaterialApp` | ||
542 | - | ||
543 | -```dart | ||
544 | -GetMaterialApp( | ||
545 | - enableLog: true, | ||
546 | - defaultTransition: Transition.fade, | ||
547 | - opaqueRoute: Get.isOpaqueRouteDefault, | ||
548 | - popGesture: Get.isPopGestureEnable, | ||
549 | - transitionDuration: Get.defaultDurationTransition, | ||
550 | - defaultGlobalState: Get.defaultGlobalState, | ||
551 | -); | ||
552 | - | ||
553 | -Get.config( | ||
554 | - enableLog = true, | ||
555 | - defaultPopGesture = true, | ||
556 | - defaultTransition = Transitions.cupertino | ||
557 | -) | ||
558 | -``` | ||
559 | - | ||
560 | -You can optionally redirect all the logging messages from `Get`. | ||
561 | -If you want to use your own, favourite logging package, | ||
562 | -and want to capture the logs there: | ||
563 | - | ||
564 | -```dart | ||
565 | -GetMaterialApp( | ||
566 | - enableLog: true, | ||
567 | - logWriterCallback: localLogWriter, | ||
568 | -); | ||
569 | - | ||
570 | -void localLogWriter(String text, {bool isError = false}) { | ||
571 | - // pass the message to your favourite logging package here | ||
572 | - // please note that even if enableLog: false log messages will be pushed in this callback | ||
573 | - // you get check the flag if you want through GetConfig.isLogEnable | ||
574 | -} | ||
575 | - | ||
576 | -``` | ||
577 | - | ||
578 | -### Local State Widgets | ||
579 | - | ||
580 | -These Widgets allows you to manage a single value, and keep the state ephemeral and locally. | ||
581 | -We have flavours for Reactive and Simple. | ||
582 | -For instance, you might use them to toggle obscureText in a `TextField`, maybe create a custom | ||
583 | -Expandable Panel, or maybe modify the current index in `BottomNavigationBar` while changing the content | ||
584 | -of the body in a `Scaffold`. | ||
585 | - | ||
586 | -#### ValueBuilder | ||
587 | - | ||
588 | -A simplification of `StatefulWidget` that works with a `.setState` callback that takes the updated value. | ||
589 | - | ||
590 | -```dart | ||
591 | -ValueBuilder<bool>( | ||
592 | - initialValue: false, | ||
593 | - builder: (value, updateFn) => Switch( | ||
594 | - value: value, | ||
595 | - onChanged: updateFn, // same signature! you could use ( newValue ) => updateFn( newValue ) | ||
596 | - ), | ||
597 | - // if you need to call something outside the builder method. | ||
598 | - onUpdate: (value) => print("Value updated: $value"), | ||
599 | - onDispose: () => print("Widget unmounted"), | ||
600 | -), | ||
601 | -``` | ||
602 | - | ||
603 | -#### ObxValue | ||
604 | - | ||
605 | -Similar to [`ValueBuilder`](#valuebuilder), but this is the Reactive version, you pass a Rx instance (remember the magical .obs?) and | ||
606 | -updates automatically... isn't it awesome? | ||
607 | - | ||
608 | -```dart | ||
609 | -ObxValue((data) => Switch( | ||
610 | - value: data.value, | ||
611 | - onChanged: data, // Rx has a _callable_ function! You could use (flag) => data.value = flag, | ||
612 | - ), | ||
613 | - false.obs, | ||
614 | -), | ||
615 | -``` | ||
616 | - | ||
617 | -## Useful tips | ||
618 | - | ||
619 | -`.obs`ervables (also known as _Rx_ Types) have a wide variety of internal methods and operators. | ||
620 | - | ||
621 | -> Is very common to _believe_ that a property with `.obs` **IS** the actual value... but make no mistake! | ||
622 | -> We avoid the Type declaration of the variable, because Dart's compiler is smart enough, and the code | ||
623 | -> looks cleaner, but: | ||
624 | - | ||
625 | -```dart | ||
626 | -var message = 'Hello world'.obs; | ||
627 | -print( 'Message "$message" has Type ${message.runtimeType}'); | ||
628 | -``` | ||
629 | - | ||
630 | -Even if `message` _prints_ the actual String value, the Type is **RxString**! | ||
631 | - | ||
632 | -So, you can't do `message.substring( 0, 4 )`. | ||
633 | -You have to access the real `value` inside the _observable_: | ||
634 | -The most "used way" is `.value`, but, did you know that you can also use... | ||
635 | - | ||
636 | -```dart | ||
637 | -final name = 'GetX'.obs; | ||
638 | -// only "updates" the stream, if the value is different from the current one. | ||
639 | -name.value = 'Hey'; | ||
640 | - | ||
641 | -// All Rx properties are "callable" and returns the new value. | ||
642 | -// but this approach does not accepts `null`, the UI will not rebuild. | ||
643 | -name('Hello'); | ||
644 | - | ||
645 | -// is like a getter, prints 'Hello'. | ||
646 | -name() ; | ||
647 | - | ||
648 | -/// numbers: | ||
649 | - | ||
650 | -final count = 0.obs; | ||
651 | - | ||
652 | -// You can use all non mutable operations from num primitives! | ||
653 | -count + 1; | ||
654 | - | ||
655 | -// Watch out! this is only valid if `count` is not final, but var | ||
656 | -count += 1; | ||
657 | - | ||
658 | -// You can also compare against values: | ||
659 | -count > 2; | ||
660 | - | ||
661 | -/// booleans: | ||
662 | - | ||
663 | -final flag = false.obs; | ||
664 | - | ||
665 | -// switches the value between true/false | ||
666 | -flag.toggle(); | ||
667 | - | ||
668 | - | ||
669 | -/// all types: | ||
670 | - | ||
671 | -// Sets the `value` to null. | ||
672 | -flag.nil(); | ||
673 | - | ||
674 | -// All toString(), toJson() operations are passed down to the `value` | ||
675 | -print( count ); // calls `toString()` inside for RxInt | ||
676 | - | ||
677 | -final abc = [0,1,2].obs; | ||
678 | -// Converts the value to a json Array, prints RxList | ||
679 | -// Json is supported by all Rx types! | ||
680 | -print('json: ${jsonEncode(abc)}, type: ${abc.runtimeType}'); | ||
681 | - | ||
682 | -// RxMap, RxList and RxSet are special Rx types, that extends their native types. | ||
683 | -// but you can work with a List as a regular list, although is reactive! | ||
684 | -abc.add(12); // pushes 12 to the list, and UPDATES the stream. | ||
685 | -abc[3]; // like Lists, reads the index 3. | ||
686 | - | ||
687 | - | ||
688 | -// equality works with the Rx and the value, but hashCode is always taken from the value | ||
689 | -final number = 12.obs; | ||
690 | -print( number == 12 ); // prints > true | ||
691 | - | ||
692 | -/// Custom Rx Models: | ||
693 | - | ||
694 | -// toJson(), toString() are deferred to the child, so you can implement override on them, and print() the observable directly. | ||
695 | - | ||
696 | -class User { | ||
697 | - String name, last; | ||
698 | - int age; | ||
699 | - User({this.name, this.last, this.age}); | ||
700 | - | ||
701 | - @override | ||
702 | - String toString() => '$name $last, $age years old'; | ||
703 | -} | ||
704 | - | ||
705 | -final user = User(name: 'John', last: 'Doe', age: 33).obs; | ||
706 | - | ||
707 | -// `user` is "reactive", but the properties inside ARE NOT! | ||
708 | -// So, if we change some variable inside of it... | ||
709 | -user.value.name = 'Roi'; | ||
710 | -// The widget will not rebuild!, | ||
711 | -// `Rx` don't have any clue when you change something inside user. | ||
712 | -// So, for custom classes, we need to manually "notify" the change. | ||
713 | -user.refresh(); | ||
714 | - | ||
715 | -// or we can use the `update()` method! | ||
716 | -user.update((value){ | ||
717 | - value.name='Roi'; | ||
718 | -}); | ||
719 | - | ||
720 | -print( user ); | ||
721 | -``` | ||
722 | - | ||
723 | -#### GetView | ||
724 | - | ||
725 | -I love this Widget, is so simple, yet, so useful! | ||
726 | - | ||
727 | -Is a `const Stateless` Widget that has a getter `controller` for a registered `Controller`, that's all. | ||
728 | - | ||
729 | -```dart | ||
730 | - class AwesomeController extends GetxController { | ||
731 | - final String title = 'My Awesome View'; | ||
732 | - } | ||
733 | - | ||
734 | - // ALWAYS remember to pass the `Type` you used to register your controller! | ||
735 | - class AwesomeView extends GetView<AwesomeController> { | ||
736 | - @override | ||
737 | - Widget build(BuildContext context) { | ||
738 | - return Container( | ||
739 | - padding: EdgeInsets.all(20), | ||
740 | - child: Text( controller.title ), // just call `controller.something` | ||
741 | - ); | ||
742 | - } | ||
743 | - } | ||
744 | -``` | ||
745 | - | ||
746 | -#### GetWidget | ||
747 | - | ||
748 | -Most people have no idea about this Widget, or totally confuse the usage of it. | ||
749 | -The use case is very rare, but very specific: It `caches` a Controller. | ||
750 | -Because of the _cache_, can't be a `const Stateless`. | ||
751 | - | ||
752 | -> So, when do you need to "cache" a Controller? | ||
753 | - | ||
754 | -If you use, another "not so common" feature of **GetX**: `Get.create()`. | ||
755 | - | ||
756 | -`Get.create(()=>Controller())` will generate a new `Controller` each time you call | ||
757 | -`Get.find<Controller>()`, | ||
758 | - | ||
759 | -That's where `GetWidget` shines... as you can use it, for example, | ||
760 | -to keep a list of Todo items. So, if the widget gets "rebuilt", it will keep the same controller instance. | ||
761 | - | ||
762 | -#### GetxService | ||
763 | - | ||
764 | -This class is like a `GetxController`, it shares the same lifecycle ( `onInit()`, `onReady()`, `onClose()`). | ||
765 | -But has no "logic" inside of it. It just notifies **GetX** Dependency Injection system, that this subclass | ||
766 | -**can not** be removed from memory. | ||
767 | - | ||
768 | -So is super useful to keep your "Services" always reachable and active with `Get.find()`. Like: | ||
769 | -`ApiService`, `StorageService`, `CacheService`. | ||
770 | - | ||
771 | -```dart | ||
772 | -Future<void> main() async { | ||
773 | - await initServices(); /// AWAIT SERVICES INITIALIZATION. | ||
774 | - runApp(SomeApp()); | ||
775 | -} | ||
776 | - | ||
777 | -/// Is a smart move to make your Services intiialize before you run the Flutter app. | ||
778 | -/// as you can control the execution flow (maybe you need to load some Theme configuration, | ||
779 | -/// apiKey, language defined by the User... so load SettingService before running ApiService. | ||
780 | -/// so GetMaterialApp() doesnt have to rebuild, and takes the values directly. | ||
781 | -void initServices() async { | ||
782 | - print('starting services ...'); | ||
783 | - /// Here is where you put get_storage, hive, shared_pref initialization. | ||
784 | - /// or moor connection, or whatever that's async. | ||
785 | - await Get.putAsync(() => DbService().init()); | ||
786 | - await Get.putAsync(SettingsService()).init(); | ||
787 | - print('All services started...'); | ||
788 | -} | ||
789 | - | ||
790 | -class DbService extends GetxService { | ||
791 | - Future<DbService> init() async { | ||
792 | - print('$runtimeType delays 2 sec'); | ||
793 | - await 2.delay(); | ||
794 | - print('$runtimeType ready!'); | ||
795 | - return this; | ||
796 | - } | ||
797 | -} | ||
798 | - | ||
799 | -class SettingsService extends GetxService { | ||
800 | - void init() async { | ||
801 | - print('$runtimeType delays 1 sec'); | ||
802 | - await 1.delay(); | ||
803 | - print('$runtimeType ready!'); | ||
804 | - } | ||
805 | -} | ||
806 | - | ||
807 | -``` | ||
808 | - | ||
809 | -The only way to actually delete a `GetxService`, is with `Get.reset()` which is like a | ||
810 | -"Hot Reboot" of your app. So remember, if you need absolute persistance of a class instance during the | ||
811 | -lifetime of your app, use `GetxService`. | ||
812 | - | ||
813 | -# Breaking changes from 2.0 | ||
814 | - | ||
815 | -1- Rx types: | ||
816 | - | ||
817 | -| Before | After | | ||
818 | -| ------- | ---------- | | ||
819 | -| StringX | `RxString` | | ||
820 | -| IntX | `RxInt` | | ||
821 | -| MapX | `RxMap` | | ||
822 | -| ListX | `RxList` | | ||
823 | -| NumX | `RxNum` | | ||
824 | -| DoubleX | `RxDouble` | | ||
825 | - | ||
826 | -RxController and GetBuilder now have merged, you no longer need to memorize which controller you want to use, just use GetxController, it will work for simple state management and for reactive as well. | ||
827 | - | ||
828 | -2- NamedRoutes | ||
829 | -Before: | ||
830 | - | ||
831 | -```dart | ||
832 | -GetMaterialApp( | ||
833 | - namedRoutes: { | ||
834 | - '/': GetRoute(page: Home()), | ||
835 | - } | ||
836 | -) | ||
837 | -``` | ||
838 | - | ||
839 | -Now: | ||
840 | - | ||
841 | -```dart | ||
842 | -GetMaterialApp( | ||
843 | - getPages: [ | ||
844 | - GetPage(name: '/', page: () => Home()), | ||
845 | - ] | ||
846 | -) | ||
847 | -``` | ||
848 | - | ||
849 | -Why this change? | ||
850 | -Often, it may be necessary to decide which page will be displayed from a parameter, or a login token, the previous approach was inflexible, as it did not allow this. | ||
851 | -Inserting the page into a function has significantly reduced the RAM consumption, since the routes will not be allocated in memory since the app was started, and it also allowed to do this type of approach: | ||
852 | - | ||
853 | -```dart | ||
854 | - | ||
855 | -GetStorage box = GetStorage(); | ||
856 | - | ||
857 | -GetMaterialApp( | ||
858 | - getPages: [ | ||
859 | - GetPage(name: '/', page:(){ | ||
860 | - return box.hasData('token') ? Home() : Login(); | ||
861 | - }) | ||
862 | - ] | ||
863 | -) | ||
864 | -``` | ||
865 | - | ||
866 | -# Why Getx? | ||
867 | - | ||
868 | -1- Many times after a Flutter update, many of your packages will break. Sometimes compilation errors happen, errors often appear that there are still no answers about, and the developer needs to know where the error came from, track the error, only then try to open an issue in the corresponding repository, and see its problem solved. Get centralizes the main resources for development (State, dependency and route management), allowing you to add a single package to your pubspec, and start working. After a Flutter update, the only thing you need to do is update the Get dependency, and get to work. Get also resolves compatibility issues. How many times a version of a package is not compatible with the version of another, because one uses a dependency in one version, and the other in another version? This is also not a concern using Get, as everything is in the same package and is fully compatible. | ||
869 | - | ||
870 | -2- Flutter is easy, Flutter is incredible, but Flutter still has some boilerplate that may be unwanted for most developers, such as `Navigator.of(context).push (context, builder [...]`. Get simplifies development. Instead of writing 8 lines of code to just call a route, you can just do it: `Get.to(Home())` and you're done, you'll go to the next page. Dynamic web urls are a really painful thing to do with Flutter currently, and that with GetX is stupidly simple. Managing states in Flutter, and managing dependencies is also something that generates a lot of discussion, as there are hundreds of patterns in the pub. But there is nothing as easy as adding a ".obs" at the end of your variable, and place your widget inside an Obx, and that's it, all updates to that variable will be automatically updated on the screen. | ||
871 | - | ||
872 | -3- Ease without worrying about performance. Flutter's performance is already amazing, but imagine that you use a state manager, and a locator to distribute your blocs/stores/controllers/ etc. classes. You will have to manually call the exclusion of that dependency when you don't need it. But have you ever thought of simply using your controller, and when it was no longer being used by anyone, it would simply be deleted from memory? That's what GetX does. With SmartManagement, everything that is not being used is deleted from memory, and you shouldn't have to worry about anything but programming. You will be assured that you are consuming the minimum necessary resources, without even having created a logic for this. | ||
873 | - | ||
874 | -4- Actual decoupling. You may have heard the concept "separate the view from the business logic". This is not a peculiarity of BLoC, MVC, MVVM, and any other standard on the market has this concept. However, this concept can often be mitigated in Flutter due to the use of context. | ||
875 | -If you need context to find an InheritedWidget, you need it in the view, or pass the context by parameter. I particularly find this solution very ugly, and to work in teams we will always have a dependence on View's business logic. Getx is unorthodox with the standard approach, and while it does not completely ban the use of StatefulWidgets, InitState, etc., it always has a similar approach that can be cleaner. Controllers have life cycles, and when you need to make an APIREST request for example, you don't depend on anything in the view. You can use onInit to initiate the http call, and when the data arrives, the variables will be populated. As GetX is fully reactive (really, and works under streams), once the items are filled, all widgets that use that variable will be automatically updated in the view. This allows people with UI expertise to work only with widgets, and not have to send anything to business logic other than user events (like clicking a button), while people working with business logic will be free to create and test the business logic separately. | ||
876 | - | ||
877 | -This library will always be updated and implementing new features. Feel free to offer PRs and contribute to them. | ||
878 | - | ||
879 | -# Community | ||
880 | - | ||
881 | -## Community channels | ||
882 | - | ||
883 | -GetX has a highly active and helpful community. If you have questions, or would like any assistance regarding the use of this framework, please join our community channels, your question will be answered more quickly, and it will be the most suitable place. This repository is exclusive for opening issues, and requesting resources, but feel free to be part of GetX Community. | ||
884 | - | ||
885 | -| **Slack** | **Discord** | **Telegram** | | ||
886 | -| :-------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------- | | ||
887 | -| [](https://communityinviter.com/apps/getxworkspace/getx) | [](https://discord.com/invite/9Hpt99N) | [](https://t.me/joinchat/PhdbJRmsZNpAqSLJL6bH7g) | | ||
888 | - | ||
889 | -## How to contribute | ||
890 | - | ||
891 | -_Want to contribute to the project? We will be proud to highlight you as one of our collaborators. Here are some points where you can contribute and make Get (and Flutter) even better._ | ||
892 | - | ||
893 | -- Helping to translate the readme into other languages. | ||
894 | -- Adding documentation to the readme (a lot of Get's functions haven't been documented yet). | ||
895 | -- Write articles or make videos teaching how to use Get (they will be inserted in the Readme and in the future in our Wiki). | ||
896 | -- Offering PRs for code/tests. | ||
897 | -- Including new functions. | ||
898 | - | ||
899 | -Any contribution is welcome! | ||
900 | - | ||
901 | -## Articles and videos | ||
902 | - | ||
903 | -- [Dynamic Themes in 3 lines using GetX™](https://medium.com/swlh/flutter-dynamic-themes-in-3-lines-c3b375f292e3) - Tutorial by [Rod Brown](https://github.com/RodBr). | ||
904 | -- [Complete GetX™ Navigation](https://www.youtube.com/watch?v=RaqPIoJSTtI) - Route management video by Amateur Coder. | ||
905 | -- [Complete GetX State Management](https://www.youtube.com/watch?v=CNpXbeI_slw) - State management video by Amateur Coder. | ||
906 | -- [GetX™ Other Features](https://youtu.be/ttQtlX_Q0eU) - Utils, storage, bindings and other features video by Amateur Coder. | ||
907 | -- [Firestore User with GetX | Todo App](https://www.youtube.com/watch?v=BiV0DcXgk58) - Video by Amateur Coder. | ||
908 | -- [Firebase Auth with GetX | Todo App](https://www.youtube.com/watch?v=-H-T_BSgfOE) - Video by Amateur Coder. | ||
909 | -- [The Flutter GetX™ Ecosystem ~ State Management](https://medium.com/flutter-community/the-flutter-getx-ecosystem-state-management-881c7235511d) - State management by [Aachman Garg](https://github.com/imaachman). | ||
910 | -- [GetX, the all-in-one Flutter package](https://www.youtube.com/watch?v=IYQgtu9TM74) - A brief tutorial covering State Management and Navigation by Thad Carnevalli. | ||
911 | -- [Build a To-do List App from scratch using Flutter and GetX](https://www.youtube.com/watch?v=EcnqFasHf18) - UI + State Management + Storage video by Thad Carnevalli. | ||
912 | -- [GetX Flutter Firebase Auth Example](https://medium.com/@jeffmcmorris/getx-flutter-firebase-auth-example-b383c1dd1de2) - Article by Jeff McMorris. |
getx/README.pl.md
deleted
100644 → 0
1 | - | ||
2 | - | ||
3 | -*Languages: [English](README.md), [Brazilian Portuguese](README.pt-br.md), [Spanish](README-es.md), Polish (Jesteś tu).* | ||
4 | - | ||
5 | -[](https://pub.dev/packages/get) | ||
6 | - | ||
7 | -[](https://pub.dev/packages/effective_dart) | ||
8 | -[](https://discord.com/invite/9Hpt99N) | ||
9 | -[](https://communityinviter.com/apps/getxworkspace/getx) | ||
10 | -[](https://t.me/joinchat/PhdbJRmsZNpAqSLJL6bH7g) | ||
11 | -<a href="https://github.com/Solido/awesome-flutter"> | ||
12 | - <img alt="Awesome Flutter" src="https://img.shields.io/badge/Awesome-Flutter-blue.svg?longCache=true&style=flat-square" /> | ||
13 | -</a> | ||
14 | -<a href="https://www.buymeacoffee.com/jonataslaw" target="_blank"><img src="https://i.imgur.com/aV6DDA7.png" alt="Buy Me A Coffee" style="height: 41px !important;width: 174px !important; box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;" > </a> | ||
15 | - | ||
16 | - | ||
17 | - | ||
18 | - | ||
19 | -- [Kanały komunikacji i wsparcia:](#kanały-komunikacji-i-wsparcia) | ||
20 | -- [Wprowadzenie](#wprowadzenie) | ||
21 | -- [Instalacja](#instalacja) | ||
22 | -- [Counter App z GetX](#counter-app-z-getx) | ||
23 | -- [Trzy fialary](#trzy-filary) | ||
24 | - - [Menadżer stanu](#menadżer-stanu) | ||
25 | - - [Reaktywny menadżer stanu](#reaktywny-menadżer-stanu) | ||
26 | - - [Bardziej szczegółowo o menadżerze stanu](#bardziej-szczegółowo-o-menadżerze-stanu) | ||
27 | - - [Video tłumaczące użycie menadżera stanu](#video-tłumaczące-użycie-menadżera-stanu) | ||
28 | - - [Zarzadzanie routami](#zarządzanie-routami) | ||
29 | - - [Więcej o routach](#więcej-o-routach) | ||
30 | - - [Video tłumaczące użycie](#video-tłumaczące-użycie) | ||
31 | - - [Zarządzanie dependencies](#zarządzanie-dependencies) | ||
32 | - - [Bardziej szczefółowo o menadżerze dependencies](#bardziej-szczegółowo-o-menadżerze-dependencies) | ||
33 | -- [Jak włożyć coś od siebie](#jak-włożyć-coś-od-siebie) | ||
34 | -- [Narzędzia](#narzędzia) | ||
35 | - - [Zmiana motywu](#zmiana-motywu) | ||
36 | - - [Inne zaawansowane API](#inne-zaawansowane-api) | ||
37 | - - [Opcjonalne globalne ustawienia i manualna konfiguracja](#opcjonalne-globalne-ustawienia-i-manualna-konfiguracja) | ||
38 | - - [Video tłumaczace inne funkcjonalności GetX](#video-tłumaczące-inne-funkcjonalności-getx) | ||
39 | -- [Zmiany od 2.0](#zmiany-od-20) | ||
40 | - | ||
41 | - | ||
42 | -# Kanały komunikacji i wsparcia: | ||
43 | - | ||
44 | -[**Slack (English)**](https://communityinviter.com/apps/getxworkspace/getx) | ||
45 | - | ||
46 | -[**Discord (English and Portuguese)**](https://discord.com/invite/9Hpt99N) | ||
47 | - | ||
48 | -[**Telegram (Portuguese)**](https://t.me/joinchat/PhdbJRmsZNpAqSLJL6bH7g) | ||
49 | - | ||
50 | -# Wprowadzenie | ||
51 | -- GetX jest bardzo lekką i potężną biblioteką do Flattera. Łączy wysoką wydajność menadżera stanu, inteligętne dodawanie dependencies i zarządzanie routami w szybki i praktyczny sposób. | ||
52 | -- GetX nie jest dla wszystkich, skupia się na jak najmniejszej konsumpcji zasobów (wydajności) ([zobacz benchmarki](https://github.com/jonataslaw/benchmarks)), używaniu łatwej skłani (produktywności) i daniu możliwości pełnego rozbicia View na z logiki biznesowej (organizacja). | ||
53 | -- GetX która da Ci supermoce i zwiększy produktywność w tworzeniu projektu. Oszczędzi godziny zarówno początkującym jak i ekspoertom. | ||
54 | -- Nawiguj bez podawania `context`, używaj open `dialogs`, `snackbarów` oraz `bottomsheetów` z każdego miejsca w kodzie. Zarządzaj stanami i dodawaj dependencies w prosty i praktyczny sposób! | ||
55 | -- Get jest bezpieczny, stabilny i aktualny. Oprócz tego oferuje szeroki zakres API, które nie są zawarte w standardowym frameworku. | ||
56 | -- GetX nie jest przytłaczający. Ma wiele funkcjonalności pozwalajacych na rozpoczęcie programowania bez martwienia się o nic, ale wszystkie te funkcjonalności są w osobnych kontenerach będących dodane dopiero po ich użyciu. Jeśli tylko używasz menadżera stanu, tylko on będzie kompilowany. Jeśli używasz routów, lecz nic z menadżera stanu on nie będzie kompilowany. Możesz skompilować repozytorium benchmark i zobaczysz że używa tylko menadżera stanu. Aplikacje używajace Get są mniejsze niz inne ponieważ wszystkie rozwiązania GetX sa projektowane dla lekkości i wydajności. Jest to też zasługa Flutterowego AOT, które jest niesamowite i eliminuje nieużywane zasoby jak żaden inny framework. | ||
57 | - | ||
58 | -**GetX zwiększa stwoja produktywność, lecz mozesz to jeszcze przyspieszyć instalując rozszerzenie [GetX extension](https://marketplace.visualstudio.com/items?itemName=get-snippets.get-snippets) do swojego VSCode**. Jeszcze nie dostępne w innych IDE. | ||
59 | - | ||
60 | -# Instalacja | ||
61 | - | ||
62 | -Dodaj Get do swojego pliku pubspec.yaml: | ||
63 | - | ||
64 | -```yaml | ||
65 | -dependencies: | ||
66 | - get: | ||
67 | -``` | ||
68 | - | ||
69 | -Zaimportuj Get do plików w których chcesz go użyć: | ||
70 | - | ||
71 | -```dart | ||
72 | -import 'package:get/get.dart'; | ||
73 | -``` | ||
74 | - | ||
75 | -# Counter App z GetX | ||
76 | - | ||
77 | -Przykładowa aplikaja tworzona domyślnie podczas kreacji nowego projektu we Flaterze ma ponad 100 lini kodu (z komentarzami). By pokazać siłę Get pokarzę jak zrobić "licznik" ze zmienianą stan z każdym kliknięciem, zmianą stron i udostępniajac stan pomiędzy ekranami. Wszystko w zorganizowany sposób dzieląc buissnes logic z view w zaledwie 26 LINI KODU WŁĄCZAJĄC W TO KOMENTARZE. | ||
78 | - | ||
79 | --Krok 1: | ||
80 | -Dodaj "Get" przed MaterialApp, zamieniając je na GetMaterialApp | ||
81 | - | ||
82 | - | ||
83 | -```dart | ||
84 | -void main() => runApp(GetMaterialApp(home: Home())); | ||
85 | -``` | ||
86 | - | ||
87 | -- Note: nie jest to modyfikaja MaterialApp, ponieważ GetMaterialApp nie jest zmodyfikowanym MaterialApp z Fluttera, jest tylko zkonfigurowanym Widgetem mającym domyślnie MaterialApp jako dziecko. Możesz to konfigurować ręcznie, ale nie jest to konieczne. GetMaterialApp jest niezbędne dla działania routów, snackbarów, bootomsheetów, internacjonalizacji, dialogów i wysokopoziomowych api powiązanych z routami i nieobecnościa kontekstu. Nie jest to jednak wymagane do używania zarzadzania stanem i dependencies. | ||
88 | - | ||
89 | --Krok 2: | ||
90 | -Tworzymy klasę business logic i umieszczmy w niej wszystkie zmienne, metody oraz kontrolery. Możesz zmienić zmienna=ą na obserwowalną używajac prostego ".obs" | ||
91 | - | ||
92 | -```dart | ||
93 | -class Controller extends GetxController{ | ||
94 | - var count = 0.obs; | ||
95 | - increment() => count.value++; | ||
96 | -} | ||
97 | -``` | ||
98 | -- Krok 3: | ||
99 | -Tworzymy View. Użyj StatelessWidget oszczędzajac przy tym RAM. Z Get nie będzie Ci potrzebny StatefullWidget. | ||
100 | - | ||
101 | - | ||
102 | -```dart | ||
103 | -class Home extends StatelessWidget { | ||
104 | - | ||
105 | - // Instantiate your class using Get.put() to make it available for all "child" routes there. | ||
106 | - final Controller c = Get.put(Controller()); | ||
107 | - | ||
108 | - @override | ||
109 | - Widget build(context) => Scaffold( | ||
110 | - // Use Obx(()=> to update Text() whenever count is changed. | ||
111 | - appBar: AppBar(title: Obx(() => Text("Clicks: " + c.count.string))), | ||
112 | - | ||
113 | - // Replace the 8 lines Navigator.push by a simple Get.to(). You don't need context | ||
114 | - body: Center(child: RaisedButton( | ||
115 | - child: Text("Go to Other"), onPressed: () => Get.to(Other()))), | ||
116 | - floatingActionButton: | ||
117 | - FloatingActionButton(child: Icon(Icons.add), onPressed: c.increment)); | ||
118 | -} | ||
119 | - | ||
120 | -class Other extends StatelessWidget { | ||
121 | - // You can ask Get to find a Controller that is being used by another page and redirect you to it. | ||
122 | - final Controller c = Get.find(); | ||
123 | - | ||
124 | - @override | ||
125 | - Widget build(context){ | ||
126 | - // Access the updated count variable | ||
127 | - return Scaffold(body: Center(child: Text(c.count.string))); | ||
128 | - } | ||
129 | -} | ||
130 | -``` | ||
131 | -Wynik: | ||
132 | - | ||
133 | - | ||
134 | - | ||
135 | -Jest to prosty projekt, ale już na jego przykładzie widać potęgę Get. Wzraz ze wzrostem rozmiaru aplikacji ta różnica tylko się powieksza. | ||
136 | - | ||
137 | -Get był projektowany dla pracy z zespołem, ale równie dobrze sprawdza się w indywidualnej pracy. | ||
138 | - | ||
139 | -Zawsze dotrzymuj deadlinów i dostarczaj swoje rozwiązania na czas bez straty na wydajności. Get nie jest dla wszystkich jak już wspominałem, ale jeśli identyfikujesz się z powyższym zdaniem Get jest dla ciebie. | ||
140 | - | ||
141 | -# Trzy filary | ||
142 | - | ||
143 | -## Menadżer stanu | ||
144 | - | ||
145 | -Obecnie istnieje kilka menadżeów dla Fluttera. Jednak większość z nich wymaga używania ChangeNotifier, po to aby zaktualizować widżety, co nie sprawdza się pod kątem wydajności w średnich i dużych aplikacach. Możesz sprawdzić w oficjalnej dokumentacji, że ChangeNotifier powinien być używany z maksimum dwoma listinerami (https://api.flutter.dev/flutter/foundation/ChangeNotifier-class.html), będąc praktycznie bezużytecznym w średnich i duzych projektach. | ||
146 | - | ||
147 | -Get nie jest ani lepszy, ani gorszy od innych menadżerów stanów, ale powinieneś rozpatrzyć te punkty jak i poniższe, aby wybrać między użyciem Get w czystej formie (Vanilla), albo używaniem go wraz z innym menadżerem. | ||
148 | - | ||
149 | -Definitywnie Get nie jest przeciwnikiem żadnego innego menadżera, ponieważ jest on mikroframeworkiem, nie tylko menadżerem stanu. Może być użyty samodzielnie, lub w koegzystencji. | ||
150 | - | ||
151 | -Get ma bardzo lekki i prosty menadżer stanu (napisany w tylko 95 lini kodu), który nie używa ChangeNotifier. Sprosta on wymaganiom szczególnie nowych we Flutterze i nie sprawi problemu nawer w dużych aplikacjach. | ||
152 | - | ||
153 | -### Reaktywny menadżer stanu | ||
154 | - | ||
155 | -Reaktywne programowanie możee dotrącać niektórych, ponieważ powszechnie jest uważane za skomplikowane. GetX zamienia to w coś prostego: | ||
156 | - | ||
157 | -- Nie musisz tworzyć Strw=eamControllerów, | ||
158 | -- Nie musisz tworzyć StreamBuildera dla każdej zmiennej, | ||
159 | -- Nie ma potrzeby tworzenia klasy dla kżdego stanu, | ||
160 | -- Nie musisz tworzyć Get dla inicjalnej zmiennej | ||
161 | - | ||
162 | -Wyobraź sobie, że masz zmienną i za każdym razem jak zmienisz ją chcesz żeby wszystkie widżety używające jej automatycznie się zmieniły | ||
163 | - | ||
164 | -Przykładowa zmienna: | ||
165 | -```dart | ||
166 | -var name = 'Jonatas Borges'; | ||
167 | -``` | ||
168 | - | ||
169 | -By zamienić ją na obserwowalną dodaj ".obx" na końcu: | ||
170 | - | ||
171 | -```dart | ||
172 | -var name = 'Jonatas Borges'.obs; | ||
173 | -``` | ||
174 | - | ||
175 | -I w UI, kiedy chcesz go zaktualizować przy modyfikacji zmiennej po prostu dodaj to: | ||
176 | -```dart | ||
177 | -Obx (() => Text (controller.name)); | ||
178 | -``` | ||
179 | - | ||
180 | -To wszystko. *Proste*, co nie? | ||
181 | - | ||
182 | -### Bardziej szczegółowo o menadżerze stanu | ||
183 | -**Zobacz bardziej szczegółowe wytłumaczenie menadz=żera sranu [tutaj](./documentation/en_US/state_management.md). Znajdują się tam przykłady jak o różnice między prostym menadżerem stanu oraz reaktywnym** | ||
184 | - | ||
185 | -### Video tłumaczące użycie menadżera stanu | ||
186 | - | ||
187 | -Amateur COder nagrał o tym niezwykły film: | ||
188 | - | ||
189 | -Link: [Complete GetX State Management](https://www.youtube.com/watch?v=CNpXbeI_slw) | ||
190 | - | ||
191 | -## Zarządzanie routami | ||
192 | - | ||
193 | -Jeśli chcesz używać routes/snackbars/dialogs/bottomsheets z GetX możesz to robić bez contextu. | ||
194 | - | ||
195 | -Zamień MaterialApp na GetMaterialApp | ||
196 | -```dart | ||
197 | -GetMaterialApp( // Before: MaterialApp( | ||
198 | - home: MyHome(), | ||
199 | -) | ||
200 | -``` | ||
201 | - | ||
202 | -By nawigować do nowego ekranu: | ||
203 | - | ||
204 | -```dart | ||
205 | -Get.to(NextScreen()); | ||
206 | -``` | ||
207 | - | ||
208 | -By powrócić do poprzedniego ekranu | ||
209 | - | ||
210 | -```dart | ||
211 | -Get.back(); | ||
212 | -``` | ||
213 | - | ||
214 | -By przejść do następnego ekranu bez możliwości powrotu do poprzedniego (do zastosowania SplashScreenów, ekranów logowania itd.) | ||
215 | - | ||
216 | -```dart | ||
217 | -Get.off(NextScreen()); | ||
218 | -``` | ||
219 | - | ||
220 | -By przejść do następnego ekranu niszcząc poprzednie routy (użyteczne w koszykach, ankietach i testach) | ||
221 | - | ||
222 | -```dart | ||
223 | -Get.offAll(NextScreen()); | ||
224 | -``` | ||
225 | - | ||
226 | -By nawigować do następnego routa i otrzymać, lub uaktualnić dane zaraz po tym jak z niego wrócisz: | ||
227 | -```dart | ||
228 | -var data = await Get.to(Payment()); | ||
229 | -``` | ||
230 | -w innym ekranie wyślij dane z poprzedniego routa:featury | ||
231 | - | ||
232 | -```dart | ||
233 | -Get.back(result: 'sucess'); | ||
234 | -``` | ||
235 | -I użyj następujące np.: | ||
236 | -```dart | ||
237 | -if(data == 'sucess') madeAnything(); | ||
238 | -``` | ||
239 | -Zobacz, ze do żadnej z tych operacji nie potrzebowałeś contextu. Jest to jedna z głównych zalet GetX oszczędzającego na niepotrzebnej ogudowie z kod i dającego możliwość uzywania tych metod w klasie kontrolera. | ||
240 | - | ||
241 | - | ||
242 | -### Więcej o routach | ||
243 | - | ||
244 | -**Get używa named routes i także oferuje niskopoziomową obsługę routów! Zobacz bardziej szczegółową dokumentacje [tutaj](./documentation/en_US/route_management.md)** | ||
245 | - | ||
246 | -### Video tłumaczące użycie | ||
247 | - | ||
248 | -Amateur Coder nagrał o tym niezwykły film: | ||
249 | - | ||
250 | -Link: [Complete GetX Navigation](https://www.youtube.com/watch?v=RaqPIoJSTtI) | ||
251 | - | ||
252 | -## Zarządzanie dependencies | ||
253 | - | ||
254 | -Get ma prosty i potężny menadżer dependencies. Pozwala on na otrzymanie tych samych klas jak twoje Bloc lub Kontroler piszac jedną linię kodu bez Provider context i inheritedWidget: | ||
255 | - | ||
256 | -```dart | ||
257 | -Controller controller = Get.put(Controller()); // Rather Controller controller = Controller(); | ||
258 | -``` | ||
259 | - | ||
260 | -- Note: Jeśli używasz menadżera stanu Get zwróć uwafę na binding api, które pozwoli Ci łatwiej połączyć twój widok z kontrolerem. | ||
261 | -https://github.com/jonataslaw/get | ||
262 | -**Tip:** Menadżer dependency Get jest oddzielony od innych części pakietu więc jeśli już używasz menadzera stanu(którego kolwiek,bez różnicy) nie musisz przepisywać tego wszystkiego na nowo. Możesz używać tego dodawania dependencies bez poroblemu. | ||
263 | - | ||
264 | -```dart | ||
265 | -controller.fetchApi(); | ||
266 | -``` | ||
267 | -Wyobraź sobie, że musisz nawigować pomiędzy wieloma routami i potrzebujesz dane z kontrolerów z poprzednich ekranów. Musiałbyś użyć menadżera stanu z dodatkiem Providera albo Get_it, prawda? Otuż nie z Fet. Muszisz po prostu poprosić Get o znalezienie tego kontrolera i nie potrzebujesz przy tym dodatkowych dependencies. | ||
268 | - | ||
269 | -```dart | ||
270 | -Controller controller = Get.find(); | ||
271 | -//Yes, it looks like Magic, Get will find your controller, and will deliver it to you. You can have 1 million controllersfeatury instantiated, Get will always give you the right controller. | ||
272 | -``` | ||
273 | - | ||
274 | -I wtedy będziesz mógł otrzymać bez problemu z niego dane | ||
275 | - | ||
276 | -```dart | ||
277 | -Text(controller.textFromApi); | ||
278 | -``` | ||
279 | -### Bardziej szczegółowo o menadżerze dependencies | ||
280 | - | ||
281 | -**Zobzcz więcej w dokumentacji [tutaj](./documentation/en_US/dependency_management.md)** | ||
282 | - | ||
283 | -# Jak włożyć coś od siebie | ||
284 | - | ||
285 | -Możesz uczestniczyć w rozwoju projektu na różny sposób: | ||
286 | -- Pomagając w tłumaczeniu readme na inne języki. | ||
287 | -- Dodając dokumentację do readme ( nawet nie połowa funkcji została jeszcze opisana). | ||
288 | -- Pisząc artykuły i nagrywając filmy uczące użycia biblioteki Get (będą zamieszczone w readme, a w przyszłości na naszej Wiki). | ||
289 | -- Oferując PR-y dla kodu i testów. | ||
290 | -- Dodając nowe funkcje. | ||
291 | - | ||
292 | -Każda współpraca jest mile widziana! | ||
293 | - | ||
294 | -# Narzędzia | ||
295 | - | ||
296 | -## Zmiana motywu | ||
297 | - | ||
298 | -Nie powinno się uzywać innego widżetu niż GetMaterialApp by go zaktualizować. To może powodować duplikacje kluczy. Wiele osób nawykło do prehistorycznego podejścia tworzenia widżetu "ThemeProvider" tylko po to by zmienić motyw aplikacji. Z Get nie jest to absolutnie wymagane. | ||
299 | - | ||
300 | -Możesz stworzyć customowy motyw i łatwo go dodać z Get.changeTheme bez niepotrzebnego kodu. | ||
301 | - | ||
302 | -```dart | ||
303 | -Get.changeTheme(ThemeData.light()); | ||
304 | -``` | ||
305 | - | ||
306 | -Jeśli chcesz stworzyć coś jak przycisk zmieniający motyw aplikacji na onTap, możesz połączyć dwia Get API. Api sprawdzające czy ciemny motyw jest używany i Api zajmujące się zmianą motywu. Po prostu użyj tego w onPressed: | ||
307 | - | ||
308 | -```dart | ||
309 | -Get.changeTheme(Get.isDarkMode? ThemeData.light(): ThemeData.dark());featury | ||
310 | -``` | ||
311 | - | ||
312 | -Kiedy ciemny motyw jest aktywny zmieni się on na jasny, w przeciwnym wypadku zmieni się na ciemny. | ||
313 | - | ||
314 | -Jeśli interesuje Cię jak zmieniać motywy podąrzaj za samouczkiem na Medium uczącym zmiany motywu z Get: | ||
315 | - | ||
316 | -- [Dynamic Themes in 3 lines using Get](https://medium.com/swlh/flutter-dynamic-themes-in-3-lines-c3b375f292e3) - Samouczek stworzony przez [Rod Brown](https://github.com/RodBr). | ||
317 | - | ||
318 | -## Inne zaawansowane API | ||
319 | - | ||
320 | -```dart | ||
321 | -// give the current args from currentScreen | ||
322 | -Get.arguments | ||
323 | - | ||
324 | -// give arguments of previous route | ||
325 | -Get.previousArguments | ||
326 | - | ||
327 | -// give name of previous route | ||
328 | -Get.previousRoute | ||
329 | - | ||
330 | -// give the raw route to access for example, rawRoute.isFirst() | ||
331 | -Get.rawRoute | ||
332 | - | ||
333 | -// give access to Rounting API from GetObserver | ||
334 | -Get.routing | ||
335 | - | ||
336 | -// check if snackbar is open | ||
337 | -Get.isSnackbarOpen | ||
338 | - | ||
339 | -// check if dialog is open | ||
340 | -Get.isDialogOpen | ||
341 | - | ||
342 | -// check if bottomsheet is opefeaturyn | ||
343 | -Get.isBottomSheetOpen | ||
344 | - | ||
345 | -// remove one route. | ||
346 | -Get.removeRoute() | ||
347 | - | ||
348 | -// back repeatedly until the predicate returns true. | ||
349 | -Get.until() | ||
350 | - | ||
351 | -// go to next route and remove all the previous routes until the predicate returns true. | ||
352 | -Get.offUntil() | ||
353 | - | ||
354 | -// go to next named route and remove all the previous routes until the predicate returns true. | ||
355 | -Get.offNamedUntil() | ||
356 | - | ||
357 | -//Check in what platform the app is running | ||
358 | -GetPlatform.isAndroid | ||
359 | -GetPlatform.isIOS | ||
360 | -GetPlatform.isWeb | ||
361 | - | ||
362 | -// Equivalent to the method: MediaQuery.of(context).size.height, but they are immutable. | ||
363 | -Get.height | ||
364 | -Get.width | ||
365 | - | ||
366 | -// Gives the current context of navigator. | ||
367 | -Get.context | ||
368 | - | ||
369 | -// Gives the context of the snackbar/dialog/bottomsheet in the foreground anywhere in your code. | ||
370 | -Get.contextOverlay | ||
371 | - | ||
372 | -// Note: the following methods are extensions on context. Since you | ||
373 | -// have access to context in any place of your UI, you can use it anywhere in the UI code | ||
374 | - | ||
375 | -// If you need a changeable height/width (like browser windows that can be scfeaturyaled) you will need to use context. | ||
376 | -context.width | ||
377 | -context.height | ||
378 | - | ||
379 | -// gives you the power to define half the screen now, a third of it and so on. | ||
380 | -//Useful for responsive applications. | ||
381 | -// param dividedBy (double) optional - default: 1 | ||
382 | -// param reducedBy (double) optional - default: 0 | ||
383 | -context.heightTransformer() | ||
384 | -context.widthTransformer() | ||
385 | - | ||
386 | -/// similar to MediaQuery.of(context).size | ||
387 | -context.mediaQuerySize() | ||
388 | - | ||
389 | -/// similar to MediaQuery.of(context).padding | ||
390 | -context.mediaQueryPadding() | ||
391 | - | ||
392 | -/// similar to MediaQuery.of(context).viewPadding | ||
393 | -context.mediaQueryViewPadding() | ||
394 | - | ||
395 | -/// similar to MediaQuery.of(context).viewInsets; | ||
396 | -context.mediaQueryViewInsets() | ||
397 | - | ||
398 | -/// similar to MediaQuery.of(context).orientation; | ||
399 | -context.orientation() | ||
400 | - | ||
401 | -/// check if device is on landscape mode | ||
402 | -context.isLandscape() | ||
403 | - | ||
404 | -/// check if device is on portrait mode | ||
405 | -context.isPortrait() | ||
406 | - | ||
407 | -/// similar to MediaQuery.of(context).devicePixelRatio; | ||
408 | -context.devicePixelRatio() | ||
409 | - | ||
410 | -/// similar to MediaQuery.of(context).textScaleFactor; | ||
411 | -context.textScaleFactor() | ||
412 | - | ||
413 | -/// get the shortestSide from screen | ||
414 | -context.mediaQueryShortestSide() | ||
415 | - | ||
416 | -/// True if width be larger thfeaturyan 800 | ||
417 | -context.showNavbar() | ||
418 | - | ||
419 | -/// True if the shortestSide is smaller than 600p | ||
420 | -context.isPhone() | ||
421 | - | ||
422 | -/// True if the shortestSide is largest than 600p | ||
423 | -context.isSmallTablet() | ||
424 | - | ||
425 | -/// True if the shortestSide is largest than 720p | ||
426 | -context.isLargeTablet() | ||
427 | - | ||
428 | -/// True if the current device is Tablet | ||
429 | -context.isTablet() | ||
430 | -``` | ||
431 | - | ||
432 | -### Opcjonalne globalne ustawienia i manualna konfiguracja | ||
433 | - | ||
434 | -GetMaterialApp konfiguruje wszystko za Ciebie, ale jeśli chcesz możesz konfigurować Get manualnie. | ||
435 | - | ||
436 | -```dart | ||
437 | -MaterialApp( | ||
438 | - navigatorKey: Get.key, | ||
439 | - navigatorObservers: [GetObserver()], | ||
440 | -); | ||
441 | -``` | ||
442 | - | ||
443 | -Będziesz mógł używać swojego Midware z GetObserver, nie wpływa to na nic. | ||
444 | - | ||
445 | -```dart | ||
446 | -MaterialApp( | ||
447 | - navigatorKey: Get.key, | ||
448 | - navigatorObservers: [ | ||
449 | - GetObserver(MiddleWare.observer) // Here | ||
450 | - ], | ||
451 | -); | ||
452 | -``` | ||
453 | - | ||
454 | -Mozesz stworzyć globalne ustawienia dla Get. Tylko dodaj Get.config do swojego kodu przed użyciem routów, lub bezpośrednio w GetMaterialApp | ||
455 | - | ||
456 | -```dart | ||
457 | -GetMaterialApp( | ||
458 | - enableLog: true, | ||
459 | - defaultTransition: Transition.fade, | ||
460 | - opaqueRoute: Get.isOpaqueRouteDefault, | ||
461 | - popGesture: Get.isPopGestureEnable, | ||
462 | - transitionDuration: Get.defaultDurationTransition, | ||
463 | - defaultGlobalState: Get.defaultGlobalState,https://github.com/jonataslaw/ge | ||
464 | -); | ||
465 | - | ||
466 | -Get.config( | ||
467 | - enableLog = true, | ||
468 | - defaultPopGesture = true, | ||
469 | - defaultTransition = Transitions.cupertino | ||
470 | -) | ||
471 | -``` | ||
472 | - | ||
473 | -Opcjonalnie możesz przekierować wszystkie logi z Get by używać swojej ulubionej paczki i zbierać w niej logi. | ||
474 | - | ||
475 | -```dart | ||
476 | -GetMaterialApp( | ||
477 | - enableLog: true, | ||
478 | - logWriterCallback: localLogWriter, | ||
479 | - ); | ||
480 | - void localLogWriter(String text, {bool isError = false}) { | ||
481 | - // tutaj przekaż wiadomosci do ulubionej paczki | ||
482 | - // pamiętaj że nawet jeśli "enableLog: false" logi i tak będą wysłane w tym callbacku | ||
483 | - // Musisz sprawdzić konfiguracje flag jeśli chcesz przez GetConfig.isLogEnable | ||
484 | - } | ||
485 | -``` | ||
486 | -## Video tłumaczące inne funkcjonalności GetX | ||
487 | - | ||
488 | - | ||
489 | -Amateur Coder nagrał niezwykły film tłumaczący powyższe zagadnienia! | ||
490 | - | ||
491 | -Link: [GetX Other Features](https://youtu.be/ttQtlX_Q0eU) | ||
492 | - | ||
493 | - | ||
494 | -# Zmiany od 2.0 | ||
495 | - | ||
496 | -1- Typy Rx: | ||
497 | - | ||
498 | -| Przed | Po | | ||
499 | -| ------- | ---------- | | ||
500 | -| StringX | `RxString` | | ||
501 | -| IntX | `RxInt` | | ||
502 | -| MapX | `RxMax` | | ||
503 | -| ListX | `RxList` | | ||
504 | -| NumX | `RxNum` | | ||
505 | -| DoubleX | `RxDouble` | | ||
506 | - | ||
507 | -RXController i GetBuilder teraz zostały połączone. Nie musisz już pamiętać którego kontrolerachcesz użyć, po prostu korzystaj z GetxController, będzie działać zarówno dla prostego jak i reaktywnego menadżera stanów. | ||
508 | - | ||
509 | -2- NamedRoutes | ||
510 | -Wcześniej: | ||
511 | - | ||
512 | -```dart | ||
513 | -GetMaterialApp( | ||
514 | - namedRoutes: { | ||
515 | - '/': GetRoute(page: Home()), | ||
516 | - } | ||
517 | -) | ||
518 | -``` | ||
519 | - | ||
520 | -Teraz: | ||
521 | - | ||
522 | -```dart | ||
523 | -GetMaterialApp( | ||
524 | - getPages: [ | ||
525 | - GetPage(name: '/', page: () => Home()), | ||
526 | - ] | ||
527 | -) | ||
528 | -``` | ||
529 | - | ||
530 | -Po co ta zmiana? | ||
531 | -Często może być niezbędnym decydowanie która strona będzie wyswietlana w zależności od parametru, lub tokenu logowania. Wczesniejsze podejscie było nieelastyczne nie pozwalając na to. Zawarcie strony w funkcji zmniejszyło sporzycie RAM-u, ze względu na niealokowanie routów od początku działania aplikacji. Pozwoliło to także na takie podejscie: | ||
532 | - | ||
533 | -```dart | ||
534 | - | ||
535 | -GetStorage box = GetStorage(); | ||
536 | - | ||
537 | -GetMaterialApp( | ||
538 | - getPages: [ | ||
539 | - GetPage(name: '/', page:(){ | ||
540 | - return box.hasData('token') ? Home() : Login(); | ||
541 | - }) | ||
542 | - ] | ||
543 | -) | ||
544 | -``` |
getx/README.pt-br.md
deleted
100644 → 0
1 | - | ||
2 | - | ||
3 | -*Idiomas: [Inglês](README.md), Português Brasileiro (este arquivo), [Espanhol](README-es.md), [Polaco](README.pl.md).* | ||
4 | - | ||
5 | -[](https://pub.dev/packages/get) | ||
6 | - | ||
7 | -[](https://pub.dev/packages/effective_dart) | ||
8 | -[](https://discord.com/invite/9Hpt99N) | ||
9 | -[](https://communityinviter.com/apps/getxworkspace/getx) | ||
10 | -[](https://t.me/joinchat/PhdbJRmsZNpAqSLJL6bH7g) | ||
11 | -<a href="https://github.com/Solido/awesome-flutter"> | ||
12 | - <img alt="Awesome Flutter" src="https://img.shields.io/badge/Awesome-Flutter-blue.svg?longCache=true&style=flat-square" /> | ||
13 | -</a> | ||
14 | -<a href="https://www.buymeacoffee.com/jonataslaw" target="_blank"><img src="https://i.imgur.com/aV6DDA7.png" alt="Buy Me A Coffee" style="height: 41px !important;width: 174px !important; box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;" > </a> | ||
15 | - | ||
16 | - | ||
17 | - | ||
18 | - | ||
19 | -<h2> Pedimos desculpas por qualquer parte não traduzida aqui. O GetX™ é atualizado com muita frequência e as traduções podem não vir ao mesmo tempo. Então, para manter essa documentação pelo menos com tudo que a versão em inglês tem, eu vou deixar todos os textos não-traduzidos aqui (eu considero que é melhor ele estar lá em inglês do que não estar), então se alguém quiser traduzir, seria muito útil 😁</h2> | ||
20 | - | ||
21 | -- [Sobre Get](#sobre-get) | ||
22 | -- [Instalando](#instalando) | ||
23 | -- [App Counter usando GetX](#app-counter-usando-getx) | ||
24 | -- [Os três pilares](#os-três-pilares) | ||
25 | - - [Gerenciamento de estado](#gerenciamento-de-estado) | ||
26 | - - [Reactive state manager](#reactive-state-manager) | ||
27 | - - [Mais detalhes sobre gerenciamento de estado](#mais-detalhes-sobre-gerenciamento-de-estado) | ||
28 | - - [Explicação em video do gerenciamento de estado](#explicação-em-video-do-gerenciamento-de-estado) | ||
29 | - - [Gerenciamento de rotas](#gerenciamento-de-rotas) | ||
30 | - - [Mais detalhes sobre gerenciamento de rotas](#mais-detalhes-sobre-gerenciamento-de-rotas) | ||
31 | - - [Explicação em video do gerenciamento de rotas](#explicação-em-video-do-gerenciamento-de-rotas) | ||
32 | - - [Gerenciamento de Dependência](#gerenciamento-de-dependência) | ||
33 | - - [Mais detalhes sobre gerenciamento de dependências](#mais-detalhes-sobre-gerenciamento-de-dependências) | ||
34 | -- [Utilidades](#utilidades) | ||
35 | - - [Internacionalização](#internacionalização) | ||
36 | - - [Traduções](#traduções) | ||
37 | - - [Usando traduções](#usando-traduções) | ||
38 | - - [Localidade](#localidade) | ||
39 | - - [Alterar Local](#alterar-local) | ||
40 | - - [Localidade do sistema operacional](#localidade-do-sistema-operacional) | ||
41 | - - [Mudar tema (changeTheme)](#mudar-tema-changetheme) | ||
42 | - - [Outras APIs avançadas](#outras-apis-avançadas) | ||
43 | - - [Configurações Globais opcionais e configurações manuais](#configurações-globais-opcionais-e-configurações-manuais) | ||
44 | - - [Widgets de Estado Local](#widgets-de-estado-local) | ||
45 | - - [ValueBuilder](#valuebuilder) | ||
46 | - - [ObxValue](#obxvalue) | ||
47 | - - [Dicas Úteis](#dicas-úteis) | ||
48 | - - [GetView](#getview) | ||
49 | - - [GetWidget](#getwidget) | ||
50 | - - [GetxService](#getxservice) | ||
51 | - - [Explicação em vídeo sobre Outras Features do GetX](#explicação-em-vídeo-sobre-outras-features-do-getx) | ||
52 | -- [Breaking Changes da versão 2 para 3](#breaking-changes-da-versão-2-para-3) | ||
53 | - - [Tipagem Rx](#tipagem-rx) | ||
54 | - - [RxController e GetBuilder se uniram](#rxcontroller-e-getbuilder-se-uniram) | ||
55 | - - [Rotas nomeadas](#rotas-nomeadas) | ||
56 | - - [Porque essa mudança](#porque-essa-mudança) | ||
57 | -- [Por que GetX?](#por-que-getx) | ||
58 | -- [Comunidade](#comunidade) | ||
59 | - - [Canais da comunidade](#canais-da-comunidade) | ||
60 | - - [Como contribuir](#como-contribuir) | ||
61 | - - [Artigos e vídeos](#artigos-e-vídeos) | ||
62 | - | ||
63 | -# Sobre Get | ||
64 | - | ||
65 | -- Get é uma biblioteca poderosa e extraleve para Flutter. Ela combina um gerenciador de estado de alta performance, injeção de dependência inteligente e gerenciamento de rotas de uma forma rápida e prática. | ||
66 | -- GetX™ possui 3 princípios básicos, o que significa que esta é a prioridade para todos os recursos da biblioteca | ||
67 | - - **PERFOMANCE**: GetX™ é focado em desempenho e consumo mínimo de recursos. Os benchmarks quase sempre não são importantes no mundo real, mas se você quiser, há um indicador de consumo aqui ([benchmarks](https://github.com/jonataslaw/benchmarks)), onde GetX™ se sai melhor do que outras abordagens de gerenciamento de estado, por exemplo. A diferença não é grande, mas mostra nossa preocupação em não desperdiçar seus recursos. | ||
68 | - - **PRODUTIVIDADE**: GetX™ usa uma sintaxe fácil e agradável. Não importa o que você queira fazer, sempre há uma maneira mais fácil com GetX™. Isso economizará horas de desenvolvimento e extrairá o máximo de desempenho que seu aplicativo pode oferecer. | ||
69 | - - **ORGANIZAÇÃO**: GetX™ permite o desacoplamento total da View, lógica de apresentação, lógica de negócios, injeção de dependência e navegação. Você não precisa de contexto para navegar entre as rotas, portanto, você não depende da árvore do widget (visualização) para isso. Você não precisa de contexto para acessar seus Controllers / BLoCs por meio de um inheritedWidget, então você desacopla completamente sua lógica de apresentação e lógica de negócios de sua camada de visualização. Você não precisa injetar suas classes Controllers / Models / BLoCs em sua árvore de widgets através de multiproviders, pois GetX™ usa seu próprio recurso de injeção de dependência, desacoplando a DI de sua View completamente. Com GetX™ você sabe onde encontrar cada recurso de sua aplicação, tendo o código limpo por padrão. Isso além de facilitar a manutenção, torna o compartilhamento dos módulos, algo que até então em Flutter era impensável, algo totalmente possível. O BLoC foi um ponto de partida para organizar o código no Flutter, ele separa a lógica de negócios da visualização. GetX™ é uma evolução natural disso, separando não apenas a lógica de negócios, mas a lógica de apresentação. O bônus da injeção de dependências e rotas também são dissociadas e a camada de dados está fora de tudo. Você sabe onde está tudo e tudo isso de uma maneira mais fácil do que construir um hello world. GetX™ é a maneira mais fácil, prática e escalonável de construir aplicativos de alto desempenho com o Flutter SDK, com um grande ecossistema em torno dele que funciona perfeitamente em conjunto, sendo fácil para iniciantes e preciso para especialistas. É seguro, estável, atualizado e oferece uma grande variedade de APIs integradas que não estão presentes no Flutter SDK padrão. | ||
70 | -- GetX™ não é inchado. Possui uma infinidade de recursos que permitem que você comece a programar sem se preocupar com nada, mas cada um desses recursos está em contêineres separados e só são iniciados após o uso. Se você usar apenas o Gerenciamento de estado, apenas o Gerenciamento de estado será compilado. Se você usar apenas rotas, nada do gerenciamento de estado será compilado. Você pode compilar o repositório de benchmark e verá que usando apenas o gerenciamento de estado Get, o aplicativo compilado com Get tornou-se menor do que todos os outros aplicativos que têm apenas o gerenciamento de estado de outros pacotes, porque nada que não seja usado será compilado em seu código e cada solução GetX™ foi projetada para ser extra leve. O mérito aqui também vem do tree shaking do Flutter, que é incrível e consegue eliminar recursos não utilizados como nenhum outro framework faz. | ||
71 | -- Navegue por rotas sem `context`, abra `Dialog`s, `Snackbar`s ou `BottomSheet`s de qualquer lugar no código, gerencie estados e injete dependências de uma forma simples e prática. | ||
72 | -- GetX™ possui um enorme ecossistema, capaz de rodar com o mesmo código no Android, iOS, Web, Mac, Linux, Windows e em seu servidor. É possível reutilizar totalmente o código feito no front-end em seu back-end com **[Get Server](https://github.com/jonataslaw/get_server)**. | ||
73 | - | ||
74 | -Além disso, todo o processo de desenvolvimento pode ser totalmente automatizado, tanto no servidor quanto no front-end com **[Get CLI](https://github.com/jonataslaw/get_cli)**. | ||
75 | - | ||
76 | -Além disso, para aumentar ainda mais sua produtividade, temos a **[extensão para VSCode](https://marketplace.visualstudio.com/items?itemName=get-snippets.get-snippets)** e a **[extensão para Android Studio/Intellij](https://plugins.jetbrains.com/plugin/14975-getx-snippets)** | ||
77 | - | ||
78 | -# Instalando | ||
79 | - | ||
80 | -Adicione Get ao seu arquivo pubspec.yaml | ||
81 | - | ||
82 | -```yaml | ||
83 | -dependencies: | ||
84 | - get: | ||
85 | -``` | ||
86 | - | ||
87 | -Importe o get nos arquivos que ele for usado: | ||
88 | - | ||
89 | -```dart | ||
90 | -import 'package:get/get.dart'; | ||
91 | -``` | ||
92 | - | ||
93 | -# App Counter usando GetX | ||
94 | - | ||
95 | -O app 'Counter' criado por padrão no flutter com o comando `flutter create` tem mais de 100 linhas(incluindo os comentários). Para demonstrar o poder do Get, irei demonstrar como fazer o mesmo 'Counter' mudando o estado em cada toque trocando entre páginas e compartilhando o estado entre telas. Tudo de forma organizada, separando a lógica de negócio da View, COM SOMENTE 26 LINHAS INCLUINDO COMENTÁRIOS | ||
96 | - | ||
97 | -- Passo 1: | ||
98 | -Troque `MaterialApp` para `GetMaterialApp` | ||
99 | - | ||
100 | -```dart | ||
101 | -void main() => runApp(GetMaterialApp(home: Home())); | ||
102 | -``` | ||
103 | - | ||
104 | -- **Obs:** Isso não modifica o `MaterialApp` do Flutter, GetMaterialApp não é uma versão modificada do MaterialApp, é só um Widget pré-configurado, que tem como child o MaterialApp padrão. Você pode configurar isso manualmente, mas definitivamente não é necessário. GetMaterialApp vai criar rotas, injetá-las, injetar traduções, injetar tudo que você precisa para navegação por rotas (gerenciamento de rotas). Se você quer somente usar o gerenciador de estado ou somente o gerenciador de dependências, não é necessário usar o GetMaterialApp. Ele somente é necessário para: | ||
105 | - - Rotas | ||
106 | - - Snackbars/bottomsheets/dialogs | ||
107 | - - apis relacionadas a rotas e a ausência de `context` | ||
108 | - - Internacionalização | ||
109 | -- **Obs²:** Esse passo só é necessário se você for usar o gerenciamento de rotas (`Get.to()`, `Get.back()` e assim por diante), Se você não vai usar isso então não é necessário seguir o passo 1 | ||
110 | - | ||
111 | -- Passo 2: | ||
112 | -Cria a sua classe de regra de negócio e coloque todas as variáveis, métodos e controllers dentro dela. | ||
113 | -Você pode fazer qualquer variável observável usando um simples `.obs` | ||
114 | - | ||
115 | -```dart | ||
116 | -class Controller extends GetxController{ | ||
117 | - var count = 0.obs; | ||
118 | - increment() => count.value++; | ||
119 | -} | ||
120 | -``` | ||
121 | - | ||
122 | -- Passo 3: | ||
123 | -Crie sua View usando StatelessWidget, já que, usando Get, você não precisa mais usar StatefulWidgets. | ||
124 | - | ||
125 | -```dart | ||
126 | -class Home extends StatelessWidget { | ||
127 | - // Instancie sua classe usando Get.put() para torná-la disponível para todas as rotas subsequentes | ||
128 | - final Controller c = Get.put(Controller()); | ||
129 | - @override | ||
130 | - Widget build(context) => Scaffold( | ||
131 | - appBar: AppBar(title: Obx(() => Text("Total de cliques: ${c.count}"))), | ||
132 | - // Troque o Navigator.push de 8 linhas por um simples Get.to(). Você não precisa do 'context' | ||
133 | - body: Center(child: RaisedButton( | ||
134 | - child: Text("Ir pra Outra tela"), onPressed: () => Get.to(Outra()))), | ||
135 | - floatingActionButton: FloatingActionButton(child: | ||
136 | - Icon(Icons.add), onPressed: c.increment)); | ||
137 | -} | ||
138 | - | ||
139 | -class Outra extends StatelessWidget { | ||
140 | - // Você pode pedir o Get para encontrar o controller que foi usado em outra página e redirecionar você pra ele. | ||
141 | - final Controller c = Get.find(); | ||
142 | - @override | ||
143 | - Widget build(context) => Scaffold(body: Center(child: Text("${c.count}"))); | ||
144 | -} | ||
145 | - | ||
146 | -``` | ||
147 | - | ||
148 | -Resultado: | ||
149 | - | ||
150 | - | ||
151 | - | ||
152 | -Esse é um projeto simples mas já deixa claro o quão poderoso o Get é. Enquanto seu projeto cresce, essa diferença se torna bem mais significante. | ||
153 | - | ||
154 | -Get foi feito para funcionar com times, mas torna o trabalho de um desenvolvedor individual simples. | ||
155 | - | ||
156 | -Melhore seus prazos, entregue tudo a tempo sem perder performance. Get não é para todos, mas se você identificar com o que foi dito acima, Get é para você! | ||
157 | - | ||
158 | - | ||
159 | -# Os três pilares | ||
160 | - | ||
161 | -## Gerenciamento de estado | ||
162 | - | ||
163 | -Há atualmente vários gerenciadores de estados para o Flutter. Porém, a maioria deles envolve usar `ChangeNotifier` para atualizar os widgets e isso é uma abordagem muito ruim no quesito performance em aplicações de médio ou grande porte. Você pode checar na documentação oficial do Flutter que o [`ChangeNotifier` deveria ser usado com um ou no máximo dois listeners](https://api.flutter.dev/flutter/foundation/ChangeNotifier-class.html), fazendo-o praticamente inutilizável em qualquer aplicação média ou grande. | ||
164 | - | ||
165 | -Get não é melhor ou pior que nenhum gerenciador de estado, mas você deveria analisar esses pontos tanto quanto os argumentos abaixo para escolher entre usar Get na sua forma pura, ou usando-o em conjunto com outro gerenciador de estado. | ||
166 | - | ||
167 | -Definitivamente, Get não é o inimigo de nenhum gerenciador, porque Get é um microframework, não apenas um gerenciador, e pode ser usado tanto sozinho quanto em conjunto com eles. | ||
168 | - | ||
169 | -Get tem dois gerenciadores de estado diferentes: o simple state manager (vamos chamá-lo de GetBuilder) e o reactive state manager (que tem o nome do pacote, GetX) | ||
170 | - | ||
171 | -### Reactive state manager | ||
172 | - | ||
173 | -Programação reativa pode alienar muitas pessoas porque é dito que é complicado. GetX™ transforma a programação reativa em algo bem simples: | ||
174 | - | ||
175 | -* Você não precisa criar StreamControllers | ||
176 | -* Você não precisa criar um StreamBuilder para cada variável | ||
177 | -* Você não precisa criar uma classe para cada estado | ||
178 | -* Você não precisa criar um get para o valor inicial | ||
179 | - | ||
180 | -Programação reativa com o Get é tão fácil quanto usar setState. | ||
181 | - | ||
182 | -Vamos imaginar que você tenha uma variável e quer que toda vez que ela alterar, todos os widgets que a usam são automaticamente alterados. | ||
183 | - | ||
184 | -Essa é sua variável: | ||
185 | - | ||
186 | -```dart | ||
187 | -var name = 'Jonatas Borges'; | ||
188 | -``` | ||
189 | - | ||
190 | -Para fazer dela uma variável observável, você só precisa adicionar `.obs` no final: | ||
191 | - | ||
192 | -```dart | ||
193 | -var name = 'Jonatas Borges'.obs; | ||
194 | -``` | ||
195 | - | ||
196 | -E Na UI, quando quiser mostrar a variável e escutar as mudanças dela, simplesmente faça isso: | ||
197 | - | ||
198 | -```dart | ||
199 | -Obx (() => Text (controller.name)); | ||
200 | -``` | ||
201 | - | ||
202 | -Só isso. É *simples assim*; | ||
203 | - | ||
204 | -### Mais detalhes sobre gerenciamento de estado | ||
205 | - | ||
206 | -**Veja uma explicação mais completa do gerenciamento de estado [aqui](./documentation/pt_BR/state_management.md). Lá terá mais exemplos e também a diferença do simple state manager do reactive state manager** | ||
207 | - | ||
208 | -### Explicação em video do gerenciamento de estado | ||
209 | - | ||
210 | -Amateur Coder fez um vídeo ótimo sobre o gerenciamento de estado! (em inglês). Link: [Complete GetX State Management](https://www.youtube.com/watch?v=CNpXbeI_slw) | ||
211 | - | ||
212 | -Você vai ter uma boa idea do poder do GetX™ | ||
213 | - | ||
214 | -## Gerenciamento de rotas | ||
215 | - | ||
216 | -Se você for usar routes / snackbars / dialogs / bottomsheets sem contexto, GetX™ é excelente para você também, veja: | ||
217 | - | ||
218 | -Adicione "Get" antes do seu MaterialApp, transformando-o em GetMaterialApp | ||
219 | - | ||
220 | -```dart | ||
221 | -GetMaterialApp( // Antes: MaterialApp( | ||
222 | - home: MyHome(), | ||
223 | -) | ||
224 | -``` | ||
225 | - | ||
226 | -Para navegar para uma próxima tela: | ||
227 | - | ||
228 | -```dart | ||
229 | -Get.to(ProximaTela()); | ||
230 | -``` | ||
231 | - | ||
232 | -Para fechar snackbars, dialogs, bottomsheets, ou qualquer coisa que você normalmente fecharia com o `Navigator.pop(context)` (como por exemplo fechar a View atual e voltar para a anterior): | ||
233 | - | ||
234 | -```dart | ||
235 | -Get.back(); | ||
236 | -``` | ||
237 | - | ||
238 | -Para ir para a próxima tela e NÃO deixar opção para voltar para a tela anterior (bom para SplashScreens, telas de login e etc.): | ||
239 | - | ||
240 | -```dart | ||
241 | -Get.off(ProximaTela()); | ||
242 | -``` | ||
243 | - | ||
244 | -Para ir para a próxima tela e cancelar todas as rotas anteriores (útil em telas de carrinho, votações ou testes): | ||
245 | - | ||
246 | -```dart | ||
247 | -Get.offAll(ProximaTela()); | ||
248 | -``` | ||
249 | - | ||
250 | -Para navegar para a próxima rota e receber ou atualizar dados assim que retornar da rota: | ||
251 | - | ||
252 | -```dart | ||
253 | -var dados = await Get.to(Pagamento()); | ||
254 | -``` | ||
255 | - | ||
256 | -Notou que você não precisou usar `context` para fazer nenhuma dessas coisas? Essa é uma das maiores vantagens de usar o gerenciamento de rotas do GetX™. Com isso, você pode executar todos esse métodos de dentro da classe Controller, sem preocupações. | ||
257 | - | ||
258 | -### Mais detalhes sobre gerenciamento de rotas | ||
259 | - | ||
260 | -**GetX™ funciona com rotas nomeadas também! Veja uma explicação mais completa do gerenciamento de rotas [aqui](./documentation/pt_BR/route_management.md)** | ||
261 | - | ||
262 | -### Explicação em video do gerenciamento de rotas | ||
263 | - | ||
264 | -Amateur Coder fez um outro vídeo excelente sobre gerenciamento de rotas! Link: [Complete Getx Navigation](https://www.youtube.com/watch?v=RaqPIoJSTtI) | ||
265 | - | ||
266 | -## Gerenciamento de Dependência | ||
267 | - | ||
268 | -- Nota: Se você está usando o gerenciador de estado do Get, você não precisa se preocupar com isso, só leia a documentação, mas dê uma atenção a api `Bindings`, que vai fazer tudo isso automaticamente para você. | ||
269 | - | ||
270 | -Já está usando o Get e quer fazer seu projeto o melhor possível? Get tem um gerenciador de dependência simples e poderoso que permite você pegar a mesma classe que seu Bloc ou Controller com apenas uma linha de código, sem Provider context, sem inheritedWidget: | ||
271 | - | ||
272 | -```dart | ||
273 | -Controller controller = Get.put(Controller()); // Em vez de Controller controller = Controller(); | ||
274 | -``` | ||
275 | - | ||
276 | -Em vez de instanciar sua classe dentro da classe que você está usando, você está instanciando ele dentro da instância do Get, que vai fazer ele ficar disponível por todo o App para que então você possa usar seu controller (ou uma classe Bloc) normalmente | ||
277 | - | ||
278 | - | ||
279 | -**Dica:** O gerenciamento de dependência Get é desacoplado de outras partes do pacote, então se, por exemplo, seu aplicativo já estiver usando um gerenciador de estado (qualquer um, não importa), você não precisa reescrever tudo, você pode usar esta injeção de dependência sem problemas | ||
280 | - | ||
281 | -```dart | ||
282 | -controller.fetchApi(); | ||
283 | -``` | ||
284 | - | ||
285 | -Agora, imagine que você navegou por inúmeras rotas e precisa de dados que foram deixados para trás em seu controlador. Você precisaria de um gerenciador de estado combinado com o Provider ou Get_it, correto? Não com Get. Você só precisa pedir ao Get para "procurar" pelo seu controlador, você não precisa de nenhuma dependência adicional para isso: | ||
286 | - | ||
287 | -```dart | ||
288 | -Controller controller = Get.find(); | ||
289 | -// Sim, parece Magia, o Get irá descobrir qual é seu controller e irá te entregar. | ||
290 | -// Você pode ter 1 milhão de controllers instanciados, o Get sempre te entregará o controller correto. | ||
291 | -// Apenas se lembre de Tipar seu controller, final controller = Get.find(); por exemplo, não irá funcionar. | ||
292 | -``` | ||
293 | - | ||
294 | -E então você será capaz de recuperar os dados do seu controller que foram obtidos anteriormente: | ||
295 | - | ||
296 | -```dart | ||
297 | -Text(controller.textFromApi); | ||
298 | -``` | ||
299 | - | ||
300 | -Procurando por `lazyLoading` (carregar somente quando for usar)? Você pode declarar todos os seus controllers e eles só vão ser inicializados e chamados quando alguém precisar. Você pode fazer isso | ||
301 | - | ||
302 | -```dart | ||
303 | -Get.lazyPut<Service>(()=> ApiMock()); | ||
304 | -/// ApiMock só será chamado quando alguém usar o Get.find<Service> pela primeira vez | ||
305 | -``` | ||
306 | - | ||
307 | -### Mais detalhes sobre gerenciamento de dependências | ||
308 | - | ||
309 | -**Veja uma explicação mais completa do gerenciamento de dependência [aqui](./documentation/pt_BR/dependency_management.md)** | ||
310 | - | ||
311 | -# Utilidades | ||
312 | - | ||
313 | -## Internacionalização | ||
314 | -### Traduções | ||
315 | -Nós mantemos as traduções num simples dictionary map de chave-valor. | ||
316 | -Para adicionar traduções personalizadas, crie uma classe e estenda `Translations`. | ||
317 | - | ||
318 | -```dart | ||
319 | -import 'package:get/get.dart'; | ||
320 | - | ||
321 | -class Messages extends Translations { | ||
322 | - @override | ||
323 | - Map<String, Map<String, String>> get keys => { | ||
324 | - 'en_US': { | ||
325 | - 'hello': 'Hello World', | ||
326 | - }, | ||
327 | - 'de_DE': { | ||
328 | - 'hello': 'Hallo Welt', | ||
329 | - } | ||
330 | - }; | ||
331 | -} | ||
332 | -``` | ||
333 | - | ||
334 | -#### Usando traduções | ||
335 | -Basta anexar `.tr` a chave especificada e ela será traduzida, usando o valor atual de `Get.locale` ou `Get.fallbackLocale`. | ||
336 | -```dart | ||
337 | -Text('hello'.tr); | ||
338 | -``` | ||
339 | - | ||
340 | -### Localidade | ||
341 | -Passe parâmetros para `GetMaterialApp` definir a localidade e as traduções. | ||
342 | - | ||
343 | -```dart | ||
344 | -return GetMaterialApp( | ||
345 | - translations: Messages(), // suas traduções | ||
346 | - locale: Locale('en', 'US'), // as traduções serão exibidas para esta localidade | ||
347 | - fallbackLocale: Locale('en', 'UK'), // especifica uma localidade em caso de falha na localidade definida | ||
348 | -); | ||
349 | -``` | ||
350 | - | ||
351 | -#### Alterar local | ||
352 | -Use `Get.updateLocale(locale)` para atualizar a localidade. As traduções usarão automaticamente a nova localidade e a UI será atualizada. | ||
353 | -```dart | ||
354 | -var locale = Locale('en', 'US'); | ||
355 | -Get.updateLocale(locale); | ||
356 | -``` | ||
357 | - | ||
358 | -#### Localidade do sistema operacional | ||
359 | -Para ler a localidade do sistema operacional, você pode usar `window.locale`. | ||
360 | -```dart | ||
361 | -import 'dart:ui' as ui; | ||
362 | - | ||
363 | -return GetMaterialApp( | ||
364 | - locale: ui.window.locale, | ||
365 | -); | ||
366 | -``` | ||
367 | - | ||
368 | -## Mudar tema (changeTheme) | ||
369 | - | ||
370 | -Por favor não use widget acima do GetMaterialApp para atualizar o tema. Isso pode causar keys duplicadas. Várias pessoas estão acostumadas com o jeito normal de criar um Widget `ThemeProvider` só pra alterar o tema do app, mas isso definitivamente NÃO é necessário com GetX™. | ||
371 | - | ||
372 | -Você pode criar seu tema customizado e simplesmente adicionar dentro do `Get.changeTheme` sem nenhum boilerplate para isso: | ||
373 | - | ||
374 | -```dart | ||
375 | -Get.changeTheme(ThemeData.light()) | ||
376 | -``` | ||
377 | - | ||
378 | -Se você quer criar algo como um botão que muda o tema com o toque, você pode combinar duas APIs GetX™ pra isso: | ||
379 | -- A API que checa se o tema dark está sendo aplicado; | ||
380 | -- A API de mudar o tema e colocar isso no `onPressed:` | ||
381 | - | ||
382 | -```dart | ||
383 | -Get.changeTheme(Get.isDarkMode ? ThemeData.light() : ThemeData.dark()) | ||
384 | -``` | ||
385 | - | ||
386 | -Quando o modo Dark está ativado, ele vai trocar pro modo light e vice versa. | ||
387 | - | ||
388 | -Se você quiser saber mais como trocar o tema, você pode seguir esse tutorial no Medium que até ensina persistência do tema usando Get (e SharedPreferences): | ||
389 | - | ||
390 | -- [Dynamic Themes in 3 lines using Get](https://medium.com/swlh/flutter-dynamic-themes-in-3-lines-c3b375f292e3) - Tutorial by [Rod Brown](https://github.com/RodBr). | ||
391 | - | ||
392 | -## Outras APIs avançadas | ||
393 | - | ||
394 | -```dart | ||
395 | -// fornece os arguments da tela atual | ||
396 | -Get.arguments | ||
397 | - | ||
398 | -// fornece os arguments da rota anterior | ||
399 | -Get.previousArguments | ||
400 | - | ||
401 | -// fornece o nome da rota anterior | ||
402 | -Get.previousRoute | ||
403 | - | ||
404 | -// fornece a rota bruta para acessar por exemplo, rawRoute.isFirst() | ||
405 | -Get.rawRoute | ||
406 | - | ||
407 | -// fornece acesso a API de rotas de dentro do GetObserver | ||
408 | -Get.routing | ||
409 | - | ||
410 | -// checa se o snackbar está aberto | ||
411 | -Get.isSnackbarOpen | ||
412 | - | ||
413 | -// checa se o dialog está aberto | ||
414 | -Get.isDialogOpen | ||
415 | - | ||
416 | -// checa se o bottomsheet está aberto | ||
417 | -Get.isBottomSheetOpen | ||
418 | - | ||
419 | -// remove uma rota. | ||
420 | -Get.removeRoute() | ||
421 | - | ||
422 | -// volta repetidamente até o predicate retorne true. | ||
423 | -Get.until() | ||
424 | - | ||
425 | -// vá para a próxima rota e remove todas as rotas | ||
426 | -//anteriores até que o predicate retorne true. | ||
427 | -Get.offUntil() | ||
428 | - | ||
429 | -// vá para a próxima rota nomeada e remove todas as | ||
430 | -//rotas anteriores até que o predicate retorne true. | ||
431 | -Get.offNamedUntil() | ||
432 | - | ||
433 | -// Verifica em que plataforma o app está sendo executado | ||
434 | -// (Esse método é completamente compatível com o FlutterWeb, | ||
435 | -// diferente do método do framework "Platform.isAndroid") | ||
436 | -GetPlatform.isAndroid | ||
437 | -GetPlatform.isIOS | ||
438 | -GetPlatform.isMacOS | ||
439 | -GetPlatform.isWindows | ||
440 | -GetPlatform.isLinux | ||
441 | -GetPlatform.isFuchsia | ||
442 | - | ||
443 | -// Verifica o tipo de dispositivo | ||
444 | -GetPlatform.isMobile | ||
445 | -GetPlatform.isDesktop | ||
446 | -// Todas as plataformas são suportadas de forma independente na web! | ||
447 | -// Você pode saber se está executando dentro de um navegador | ||
448 | -// no Windows, iOS, OSX, Android, etc. | ||
449 | -GetPlatform.isWeb | ||
450 | - | ||
451 | -// Equivalente ao método: MediaQuery.of(context).size.width ou height, mas é imutável. | ||
452 | -// Significa que não irá atualizar mesmo que o tamanho da tela mude (como em navegadores ou app desktop) | ||
453 | -Get.height | ||
454 | -Get.width | ||
455 | - | ||
456 | -// fornece o context da tela em qualquer lugar do seu código. | ||
457 | -Get.context | ||
458 | - | ||
459 | -// fornece o context de snackbar/dialog/bottomsheet em qualquer lugar do seu código. | ||
460 | -Get.contextOverlay | ||
461 | - | ||
462 | -// Obs: os métodos a seguir são extensions do context. Já que se | ||
463 | -// tem acesso ao context em qualquer lugar do código da UI, você pode usar lá | ||
464 | - | ||
465 | -// Se você precisa de um width/height adaptável (como em navegadores em que a janela pode ser redimensionada) | ||
466 | -// você precisa usar 'context' | ||
467 | -context.width | ||
468 | -context.height | ||
469 | - | ||
470 | -// Dá a você agora o poder de definir metade da tela, um terço da dela e assim por diante. | ||
471 | -// Útil para aplicativos responsivos. | ||
472 | -// param dividedBy (double) opcional - default: 1 | ||
473 | -// param reducedBy (double) opcional - default: 0 | ||
474 | -context.heightTransformer() | ||
475 | -context.widthTransformer() | ||
476 | - | ||
477 | -/// similar a MediaQuery.of(context).size | ||
478 | -context.mediaQuerySize() | ||
479 | - | ||
480 | -/// similar a MediaQuery.of(this).padding | ||
481 | -context.mediaQueryPadding() | ||
482 | - | ||
483 | -/// similar a MediaQuery.of(this).viewPadding | ||
484 | -context.mediaQueryViewPadding() | ||
485 | - | ||
486 | -/// similar a MediaQuery.of(this).viewInsets; | ||
487 | -context.mediaQueryViewInsets() | ||
488 | - | ||
489 | -/// similar a MediaQuery.of(this).orientation; | ||
490 | -context.orientation() | ||
491 | - | ||
492 | -/// verifica se o dispositivo está no modo paisagem | ||
493 | -context.isLandscape() | ||
494 | - | ||
495 | -/// verifica se o dispositivo está no modo retrato | ||
496 | -context.isPortrait() | ||
497 | - | ||
498 | -/// similar a MediaQuery.of(this).devicePixelRatio; | ||
499 | -context.devicePixelRatio() | ||
500 | - | ||
501 | -/// similar a MediaQuery.of(this).textScaleFactor; | ||
502 | -context.textScaleFactor() | ||
503 | - | ||
504 | -/// obtém a menor dimensão (largura ou altura) da tela | ||
505 | -context.mediaQueryShortestSide() | ||
506 | - | ||
507 | -/// retorna True se a largura da tela for maior que 800px | ||
508 | -context.showNavbar() | ||
509 | - | ||
510 | -/// retorna True se a menor dimensão (largura ou altura) da tela for menor que 600px | ||
511 | -context.isPhone() | ||
512 | - | ||
513 | -/// retorna True se a menor dimensão (largura ou altura) da tela for maior ou igual a 600px | ||
514 | -context.isSmallTablet() | ||
515 | - | ||
516 | -/// retorna True se a menor dimensão (largura ou altura) da tela for maior ou igual a 720px | ||
517 | -context.isLargeTablet() | ||
518 | - | ||
519 | -/// retorna True se o dispositivo é um Tablet | ||
520 | -context.isTablet() | ||
521 | - | ||
522 | -/// Retorna um valor de acordo com o tamanho da tela | ||
523 | -/// Os valores possíveis são: | ||
524 | -/// swatch: se a menor dimensão (largura ou altura) da tela for menor que 300px | ||
525 | -/// mobile: se a menor dimensão (largura ou altura) da tela for menor que 600px | ||
526 | -/// tablet: se a menor dimensão (largura ou altura) da tela for menor que 1200px | ||
527 | -/// desktop: se a largura da tela é maior ou iguial a 1200px | ||
528 | -context.responsiveValue<T>() | ||
529 | -``` | ||
530 | - | ||
531 | -### Configurações Globais opcionais e configurações manuais | ||
532 | - | ||
533 | -GetMaterialApp configura tudo para você, mas se quiser configurar Get manualmente, você pode. | ||
534 | - | ||
535 | -```dart | ||
536 | -MaterialApp( | ||
537 | - navigatorKey: Get.key, | ||
538 | - navigatorObservers: [GetObserver()], | ||
539 | -); | ||
540 | -``` | ||
541 | - | ||
542 | -Você também será capaz de usar seu próprio Middleware dentro do GetObserver, isso não irá influenciar em nada. | ||
543 | - | ||
544 | -```dart | ||
545 | -MaterialApp( | ||
546 | - navigatorKey: Get.key, | ||
547 | - navigatorObservers: [ | ||
548 | - GetObserver(MiddleWare.observer) // Aqui | ||
549 | - ], | ||
550 | -); | ||
551 | -``` | ||
552 | - | ||
553 | -Você pode criar Configurações Globais para o Get. Apenas adicione `Get.config` ao seu código antes de usar qualquer rota ou faça diretamente no seu GetMaterialApp | ||
554 | - | ||
555 | -```dart | ||
556 | -GetMaterialApp( | ||
557 | - enableLog: true, | ||
558 | - defaultTransition: Transition.fade, | ||
559 | - opaqueRoute: Get.isOpaqueRouteDefault, | ||
560 | - popGesture: Get.isPopGestureEnable, | ||
561 | - transitionDuration: Get.defaultDurationTransition, | ||
562 | - defaultGlobalState: Get.defaultGlobalState, | ||
563 | -); | ||
564 | -Get.config( | ||
565 | - enableLog = true, | ||
566 | - defaultPopGesture = true, | ||
567 | - defaultTransition = Transitions.cupertino | ||
568 | -) | ||
569 | -``` | ||
570 | - | ||
571 | -É possível redirecionar todas as mensagens de log do GetX™. Útil quando se tem um package de logging e vc quer que ele lide com todos os logs | ||
572 | - | ||
573 | -```dart | ||
574 | -GetMaterialApp( | ||
575 | - enableLog: true, | ||
576 | - logWriterCallback: localLogWriter, | ||
577 | -); | ||
578 | - | ||
579 | -void localLogWriter(String text, {bool isError = false}) { | ||
580 | - // passage a mensagem para seu package de logging favorito aqui | ||
581 | - // Obs: mesmo que as mensagens de log estejam desativadas | ||
582 | - // com o comando "enableLog: false", as mensagens ainda vão passar por aqui | ||
583 | - // Você precisa checar essa config manualmente aqui se quiser respeitá-la | ||
584 | -} | ||
585 | -``` | ||
586 | - | ||
587 | -### Widgets de Estado Local | ||
588 | - | ||
589 | -Esses Widgets permitem que você gerencie um único valor e mantenha o estado efêmero e localmente. Temos versões para Reativo e Simples. Por exemplo, você pode usá-los para alternar obscureText em um `TextField`, talvez criar um painel expansível personalizado ou talvez modificar o índice atual em um `BottomNavigationBar` enquanto altera o conteúdo do corpo em um `Scaffold`. | ||
590 | - | ||
591 | -#### ValueBuilder | ||
592 | -Uma simplificação de `StatefulWidget` que funciona com um callback de `setState` que passa o valor atualizado. | ||
593 | - | ||
594 | - | ||
595 | -```dart | ||
596 | -ValueBuilder<bool>( | ||
597 | - initialValue: false, | ||
598 | - builder: (value, updateFn) => Switch( | ||
599 | - value: value, | ||
600 | - onChanged: updateFn, // mesma assinatura! Você poderia usar ( newValue ) => updateFn( newValue ) | ||
601 | - ), | ||
602 | - // se você precisa chamar algo fora do método builder. | ||
603 | - onUpdate: (value) => print("Valor atualizado: $value"), | ||
604 | - onDispose: () => print("Widget desmontado"), | ||
605 | -), | ||
606 | -``` | ||
607 | - | ||
608 | -#### ObxValue | ||
609 | -Similar a ValueBuilder, mas esta é a versão Reativa, você passa uma instância Rx (lembra do .obs mágico?) e | ||
610 | -atualiza automaticamente... não é incrível? | ||
611 | - | ||
612 | -```dart | ||
613 | -ObxValue( | ||
614 | - (data) => Switch( | ||
615 | - value: data.value, | ||
616 | - onChanged: data, // Rx tem uma função _callable_! Você poderia usar (flag) => data.value = flag, | ||
617 | - ), | ||
618 | - false.obs, | ||
619 | -), | ||
620 | -``` | ||
621 | - | ||
622 | -### Explicação em vídeo sobre Outras Features do GetX | ||
623 | - | ||
624 | -Amateur Coder fez um vídeo incrível sobre utils, storage, bindings e outras features! Link: [GetX Other Features](https://youtu.be/ttQtlX_Q0eU) | ||
625 | - | ||
626 | - | ||
627 | -## Dicas Úteis | ||
628 | - | ||
629 | -`.obs`ervables (também conhecidos como _Rx_ Types) possuem uma grande variedade de métodos e operadores internos. | ||
630 | - | ||
631 | -> É muito comum acreditar que uma propriedade com `.obs` **É** o valor real... mas não se engane! | ||
632 | -> Evitamos a declaração de tipo da variável, porque o compilador do Dart é inteligente o suficiente e o código | ||
633 | -> parece mais limpo, mas: | ||
634 | - | ||
635 | -```dart | ||
636 | -var message = 'Hello world'.obs; | ||
637 | -print( 'Message "$message" é do tipo ${message.runtimeType}'); | ||
638 | -``` | ||
639 | - | ||
640 | -Mesmo que `message` _imprima_ o valor da string, seu tipo é **RxString**! | ||
641 | - | ||
642 | -Então, você não pode fazer `message.substring( 0, 4 )`. | ||
643 | -Você tem que acessar o `valor` real dentro do _observable_: | ||
644 | -A "maneira" mais usada é utilizando `.value`, mas, você sabia que também pode usar: | ||
645 | - | ||
646 | -```dart | ||
647 | -final name = 'GetX'.obs; | ||
648 | -// apenas "atualiza" o stream, se o valor for diferente do atual. | ||
649 | -name.value = 'Hey'; | ||
650 | - | ||
651 | -// Todas as propriedades Rx são "chamáveis" e retorna o novo valor. | ||
652 | -// mas esta abordagem não aceita `null`, a UI não será reconstruída | ||
653 | -name('Hello'); | ||
654 | - | ||
655 | -// é como um getter, imprime 'Hello' | ||
656 | -name() ; | ||
657 | - | ||
658 | -/// números: | ||
659 | - | ||
660 | -final count = 0.obs; | ||
661 | - | ||
662 | -// Você pode usar todas as operações não mutáveis de um num! | ||
663 | -count + 1; | ||
664 | - | ||
665 | -// Cuidado! isso só é válido se `count` não for final, mas var | ||
666 | -count += 1; | ||
667 | - | ||
668 | -// Você também pode comparar com os valores: | ||
669 | -count > 2; | ||
670 | - | ||
671 | -/// booleans: | ||
672 | - | ||
673 | -final flag = false.obs; | ||
674 | - | ||
675 | -// mude o valor entre true/false | ||
676 | -flag.toggle(); | ||
677 | - | ||
678 | - | ||
679 | -/// todos os tipos: | ||
680 | - | ||
681 | -// Defina `value` como null. | ||
682 | -flag.nil(); | ||
683 | - | ||
684 | -// Todas as operações toString() e toJson() são passada para `value` | ||
685 | -print( count ); // chama `toString()` de RxInt | ||
686 | - | ||
687 | -final abc = [0,1,2].obs; | ||
688 | -// Converte o valor em um Array json, imprime RxList | ||
689 | -// Json é suportado por todos os Rx types! | ||
690 | -print('json: ${jsonEncode(abc)}, type: ${abc.runtimeType}'); | ||
691 | - | ||
692 | -// RxMap, RxList e RxSet são Rx types especiais, que estendem seus tipos nativos. | ||
693 | -// mas você pode trabalhar com uma lista como uma lista normal, embora seja reativa! | ||
694 | -abc.add(12); // Coloca 12 na lista, e ATUALIZA o stream. | ||
695 | -abc[3]; // como uma lista lê o índice 3. | ||
696 | - | ||
697 | -// a igualdade funciona com o Rx e o value do observável, mas o hashCode é sempre obtido do value | ||
698 | -final number = 12.obs; | ||
699 | -print( number == 12 ); // prints > true | ||
700 | - | ||
701 | -/// Rx Models personalizados: | ||
702 | - | ||
703 | -// toJson(), toString() são transferidos para o filho, para que você possa implementar | ||
704 | -// override neles e imprimir o observável diretamente. | ||
705 | - | ||
706 | -class User { | ||
707 | - String name, last; | ||
708 | - int age; | ||
709 | - User({this.name, this.last, this.age}); | ||
710 | - | ||
711 | - @override | ||
712 | - String toString() => '$name $last, $age years old'; | ||
713 | -} | ||
714 | - | ||
715 | -final user = User(name: 'John', last: 'Doe', age: 33).obs; | ||
716 | - | ||
717 | -// `user` é "reativo", mas as propriedades dentro NÃO SÃO! | ||
718 | -// Então, se mudarmos alguma variável dentro dele: | ||
719 | -user.value.name = 'Roi'; | ||
720 | -// O widget não vai reconstruir!, | ||
721 | -// `Rx` não tem nenhuma notificação quando você muda algo dentro do usuário. | ||
722 | -// Portanto, para classes personalizadas, precisamos "notificar" manualmente a mudança. | ||
723 | -user.refresh(); | ||
724 | - | ||
725 | -// ou podemos usar o método `update()`! | ||
726 | -user.update((value){ | ||
727 | - value.name='Roi'; | ||
728 | -}); | ||
729 | - | ||
730 | -print( user ); // Resultado (toString): Roi Doe, 33 years old | ||
731 | -``` | ||
732 | - | ||
733 | -#### GetView | ||
734 | - | ||
735 | -Eu amo este Widget, é tão simples, mas tão útil! | ||
736 | - | ||
737 | -É um Widget `const Stateless` que tem um getter `controller` registrado para Controller, só isso. | ||
738 | - | ||
739 | -```dart | ||
740 | -class AwesomeController extends GetxController { | ||
741 | - final String title = 'My Awesome View'; | ||
742 | -} | ||
743 | - | ||
744 | -// SEMPRE lembre de passar o `Type` que você usou para registrar seu controlador! | ||
745 | -class AwesomeView extends GetView<AwesomeController> { | ||
746 | - @override | ||
747 | - Widget build(BuildContext context) { | ||
748 | - return Container( | ||
749 | - padding: EdgeInsets.all(20), | ||
750 | - child: Text( controller.title ), // apenas chame `controller.something` | ||
751 | - ); | ||
752 | - } | ||
753 | -} | ||
754 | -``` | ||
755 | - | ||
756 | -#### GetWidget | ||
757 | - | ||
758 | -A maioria das pessoas não tem ideia sobre este widget, ou confunde totalmente o uso dele. | ||
759 | -O caso de uso é muito raro, mas muito específico: Ele armazena em `cache` um Controller. | ||
760 | -Por causa do _cache_, não pode ser um `const Stateless`. | ||
761 | - | ||
762 | -> Então, quando você precisa armazenar em "cache" um Controller? | ||
763 | - | ||
764 | -Se você usar, uma outra característica "não tão comum" de **GetX™**: `Get.create()`. | ||
765 | - | ||
766 | -`Get.create(()=>Controller())` irá gerar um novo `Controller` cada vez que você chamar | ||
767 | -`Get.find<Controller>()`, | ||
768 | - | ||
769 | -É aí que `GetWidget` brilha... já que você pode usá-lo, por exemplo, | ||
770 | -para manter uma lista de itens Todo. Portanto, se o widget for "reconstruído", ele manterá a mesma instância do controlador. | ||
771 | - | ||
772 | -#### GetxService | ||
773 | - | ||
774 | -Esta classe é como um `GetxController`, ele compartilha o mesmo ciclo de vida ( `onInit()`, `onReady()`, `onClose()`). | ||
775 | -Mas não tem "lógica" dentro dele. Ele apenas notifica o sistema de injeção de dependência do GetX™ de que esta subclasse | ||
776 | -**não pode** ser removida da memória. | ||
777 | - | ||
778 | -Portanto, é muito útil manter seus "Services" sempre acessíveis e ativos com `Get.find()`. Como: | ||
779 | -`ApiService`, `StorageService`, `CacheService`. | ||
780 | - | ||
781 | -```dart | ||
782 | -Future<void> main() async { | ||
783 | - await initServices(); /// Aguarda a inicialização dos Services. | ||
784 | - runApp(SomeApp()); | ||
785 | -} | ||
786 | - | ||
787 | -/// É uma jogada inteligente para inicializar seus services antes de executar o aplicativo Flutter, | ||
788 | -/// já que você pode controlar o fluxo de execução (talvez você precise carregar alguma configuração de tema, | ||
789 | -/// apiKey, linguagem definida pelo usuário ... então carregue SettingService antes de executar ApiService. | ||
790 | -/// então GetMaterialApp() não precisa reconstruir e obtém os valores diretamente. | ||
791 | -void initServices() async { | ||
792 | - print('iniciando serviços...'); | ||
793 | - /// Aqui é onde você coloca a inicialização de get_storage, hive, shared_pref. | ||
794 | - /// ou checa a conexão, ou o que quer que seja assíncrono. | ||
795 | - await Get.putAsync(() => DbService().init()); | ||
796 | - await Get.putAsync(SettingsService()).init(); | ||
797 | - print('Todos os serviços iniciados.'); | ||
798 | -} | ||
799 | - | ||
800 | -class DbService extends GetxService { | ||
801 | - Future<DbService> init() async { | ||
802 | - print('$runtimeType delays 2 sec'); | ||
803 | - await 2.delay(); | ||
804 | - print('$runtimeType ready!'); | ||
805 | - return this; | ||
806 | - } | ||
807 | -} | ||
808 | - | ||
809 | -class SettingsService extends GetxService { | ||
810 | - void init() async { | ||
811 | - print('$runtimeType delays 1 sec'); | ||
812 | - await 1.delay(); | ||
813 | - print('$runtimeType ready!'); | ||
814 | - } | ||
815 | -} | ||
816 | -``` | ||
817 | - | ||
818 | -A única maneira de realmente excluir um `GetxService`, é com o `Get.reset()`, que é como uma | ||
819 | -"hot restart" do seu aplicativo. Portanto, lembre-se, se você precisar de persistência absoluta de uma instância de classe durante | ||
820 | -o ciclo de vida de seu aplicativo, use GetxService. | ||
821 | - | ||
822 | - | ||
823 | -# Breaking Changes da versão 2 para 3 | ||
824 | - | ||
825 | -## Tipagem Rx | ||
826 | - | ||
827 | -| Antes | Depois | | ||
828 | -| -------- | ---------- | | ||
829 | -| StringX | `RxString` | | ||
830 | -| IntX | `RxInt` | | ||
831 | -| MapX | `RxMap` | | ||
832 | -| ListX | `RxList` | | ||
833 | -| NumX | `RxNum` | | ||
834 | -| DoubleX | `RxDouble` | | ||
835 | - | ||
836 | -## RxController e GetBuilder se uniram | ||
837 | - | ||
838 | -RxController e GetBuilder agora viraram um só, você não precisa mais memorizar qual controller quer usar, apenas coloque `GetxController`, vai funcionar para os dois gerenciamento de estados | ||
839 | - | ||
840 | -```dart | ||
841 | -//Gerenciador de estado simples | ||
842 | -class Controller extends GetXController { | ||
843 | - String nome = ''; | ||
844 | - | ||
845 | - void atualizarNome(String novoNome) { | ||
846 | - nome = novoNome; | ||
847 | - update() | ||
848 | - } | ||
849 | -} | ||
850 | -``` | ||
851 | - | ||
852 | -```dart | ||
853 | -class Controller extends GetXController { | ||
854 | - final nome = ''.obs; | ||
855 | - | ||
856 | - // não precisa de um método direto pra atualizar o nome | ||
857 | - // só usar o nome.value | ||
858 | -} | ||
859 | -``` | ||
860 | - | ||
861 | -## Rotas nomeadas | ||
862 | - | ||
863 | -Antes: | ||
864 | - | ||
865 | -```dart | ||
866 | -GetMaterialApp( | ||
867 | - namedRoutes: { | ||
868 | - '/': GetRoute(page: Home()), | ||
869 | - } | ||
870 | -) | ||
871 | -``` | ||
872 | - | ||
873 | -Agora: | ||
874 | - | ||
875 | -```dart | ||
876 | -GetMaterialApp( | ||
877 | - getPages: [ | ||
878 | - GetPage(name: '/', page: () => Home()), | ||
879 | - ] | ||
880 | -) | ||
881 | -``` | ||
882 | - | ||
883 | -### Porque essa mudança? | ||
884 | - | ||
885 | -Frequentemente, pode ser necessário decidir qual pagina vai ser mostrada ao usuário a partir de um parâmetro, como um token de login. A forma abordada anteriormente não era flexível, já que não permitia isso. | ||
886 | - | ||
887 | -Inserir a página numa função reduziu significativamente o consumo de RAM, já que as rotas não são alocadas na memória no momento que o app é iniciado e também permite fazer esse tipo de abordagem: | ||
888 | - | ||
889 | -```dart | ||
890 | - | ||
891 | -GetStorage box = GetStorage(); | ||
892 | - | ||
893 | -GetMaterialApp( | ||
894 | - getPages: [ | ||
895 | - GetPage(name: '/', page:(){ | ||
896 | - return box.hasData('token') ? Home() : Login(); | ||
897 | - }) | ||
898 | - ] | ||
899 | -) | ||
900 | -``` | ||
901 | - | ||
902 | -# Por que GetX™? | ||
903 | - | ||
904 | -1- Muitas vezes após uma atualização do Flutter, muitos dos seus packages irão quebrar. As vezes acontecem erros de compilação, muitas vezes aparecem erros que ainda não existem respostas sobre e o desenvolvedor necessita saber de onde o erro veio, rastreá-lo, para só então tentar abrir uma issue no repositório correspondente e ver seu problema resolvido. Get centraliza os principais recursos para o desenvolvimento (Gerência de estado, de dependências e de rotas), permitindo você adicionar um único package em seu pubspec e começar a trabalhar. Após uma atualização do Flutter, a única coisa que você precisa fazer é atualizar a dependencia do Get e começar a trabalhar. Get também resolve problemas de compatibilidade. Quantas vezes uma versão de um package não é compatível com a versão de outro, porque um utiliza uma dependência em uma versão e o outro em outra versão? Essa também não é uma preocupação usando Get, já que tudo está no mesmo package e é totalmente compatível. | ||
905 | - | ||
906 | -2- Flutter é fácil, Flutter é incrível, mas Flutter ainda tem algum boilerplate que pode ser indesejado para maioria dos desenvolvedores, como o Navigator.of(context).push(context, builder[...]. Get simplifica o desenvolvimento. Em vez de escrever 8 linhas de código para apenas chamar uma rota, você pode simplesmente fazer: Get.to(Home()) e pronto, você irá para a próxima página. Urls dinâmicas da web é algo realmente doloroso de fazer com o Flutter atualmente e isso com o GetX™ é estupidamente simples. Gerenciar estados no Flutter e gerenciar dependências também é algo que gera muita discussão, por haver centenas de padrões na pub. Mas não há nada que seja tão fácil quanto adicionar um ".obs" no final de sua variável, colocar o seu widget dentro de um Obx e pronto, todas atualizações daquela variável serão automaticamente atualizadas na tela. | ||
907 | - | ||
908 | -3- Facilidade sem se preocupar com desempenho. O desempenho do Flutter já é incrível, mas imagine que você use um gerenciador de estados e um locator para distribuir suas classes blocs/stores/controllers/ etc. Você deverá chamar manualmente a exclusão daquela dependência quando não precisar dela. Mas já pensou em simplesmente usar seu controlador e quando ele não tivesse mais sendo usado por ninguém, ele simplesmente fosse excluído da memória? É isso que GetX™ faz. Com o SmartManagement, tudo que não está sendo usado é excluído da memória e você não deve se preocupar em nada além de programar. Você terá garantia que está consumindo o mínimo de recursos necessários, sem ao menos ter criado uma lógica para isso. | ||
909 | - | ||
910 | -4- Desacoplamento real. Você já deve ter ouvido o conceito "separar a view da lógica de negócios". Isso não é uma peculiaridade do BLoC, MVC ou MVVM, qualquer outro padrão existente no mercado tem esse conceito. No entanto, muitas vezes esse conceito pode ser mitigado no Flutter por conta do uso do context. | ||
911 | -Se você precisa de context para localizar um InheritedWidget, você precisa disso na view ou passar o context por parâmetro. Eu particularmente acho essa solução muito feia e para trabalhar em equipes teremos sempre uma dependência da lógica de negócios da View. GetX™ é pouco ortodoxo com a abordagem padrão e apesar de não proibir totalmente o uso de StatefulWidgets, InitState e etc, ele tem sempre uma abordagem similar que pode ser mais limpa. Os controllers tem ciclos de vida e quando você precisa fazer uma solicitação APIREST por exemplo, você não depende de nada da view. Você pode usar onInit para iniciar a chamada http e quando os dados chegarem, as variáveis serão preenchidas. Como GetX™ é totalmente reativo (de verdade e trabalha sob streams), assim que os itens forem preenchidos, automaticamente será atualizado na view todos os widgets que usam aquela variável. Isso permite que as pessoas especialistas em UI trabalhem apenas com widgets e não precisem enviar nada para a lógica de negócio além de eventos do usuário (como clicar em um botão), enquanto as pessoas que trabalham com a lógica de negócio ficarão livres para criá-la e testá-la separadamente. | ||
912 | - | ||
913 | -# Comunidade | ||
914 | - | ||
915 | -## Canais da comunidade | ||
916 | - | ||
917 | -GetX™ tem uma comunidade altamente ativa e útil. Se você tiver dúvidas, ou quiser alguma ajuda com relação ao uso deste framework, por favor entre em nossos canais da comunidade, sua dúvida será respondida mais rapidamente, e será o lugar mais adequado. Este repositório é exclusivo para abertura de issues e solicitação de recursos, mas fique à vontade para fazer parte da Comunidade GetX™. | ||
918 | - | ||
919 | -| **Slack (Inglês)** | **Discord (Inglês e Português)** | **Telegram (Português)** | | ||
920 | -| :-------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------- | | ||
921 | -| [](https://communityinviter.com/apps/getxworkspace/getx) | [](https://discord.com/invite/9Hpt99N) | [](https://t.me/joinchat/PhdbJRmsZNpAqSLJL6bH7g) | | ||
922 | - | ||
923 | -## Como contribuir | ||
924 | - | ||
925 | -_Quer contribuir com o projeto? Teremos o orgulho de destacá-lo como um de nossos colaboradores. Aqui estão alguns pontos onde você pode contribuir e tornar o Get (e Flutter) ainda melhor._ | ||
926 | - | ||
927 | -- Ajudando a traduzir o readme para outros idiomas. | ||
928 | -- Adicionando documentação ao readme (muitas funções do Get ainda não foram documentadas). | ||
929 | -- Escreva artigos ou faça vídeos ensinando como usar o Get (eles serão inseridos no Readme e futuramente em nosso Wiki). | ||
930 | -- Fazendo PRs para código/testes. | ||
931 | -- Incluindo novas funções. | ||
932 | - | ||
933 | -Qualquer contribuição é bem-vinda! | ||
934 | - | ||
935 | - | ||
936 | -## Artigos e vídeos | ||
937 | - | ||
938 | -- [Dynamic Themes in 3 lines using GetX™](https://medium.com/swlh/flutter-dynamic-themes-in-3-lines-c3b375f292e3) - Tutorial by [Rod Brown](https://github.com/RodBr). (inglês) | ||
939 | -- [Complete GetX™ Navigation](https://www.youtube.com/watch?v=RaqPIoJSTtI) - Route management video by Amateur Coder. (inglês) | ||
940 | -- [Complete GetX™ State Management](https://www.youtube.com/watch?v=CNpXbeI_slw) - State management video by Amateur Coder. (inglês) | ||
941 | -- [GetX™ Other Features](https://youtu.be/ttQtlX_Q0eU) - Utils, storage, bindings and other features video by Amateur Coder. (inglês) | ||
942 | -- [Firestore User with GetX™ | Todo App](https://www.youtube.com/watch?v=BiV0DcXgk58) - Video by Amateur Coder. (inglês) | ||
943 | -- [Firebase Auth with GetX™ | Todo App](https://www.youtube.com/watch?v=-H-T_BSgfOE) - Video by Amateur Coder. (inglês) | ||
944 | -- [The Flutter GetX™ Ecosystem ~ State Management](https://medium.com/flutter-community/the-flutter-getx-ecosystem-state-management-881c7235511d) - State management by [Aachman Garg](https://github.com/imaachman). (inglês) | ||
945 | -- [GetX™, the all-in-one Flutter package](https://www.youtube.com/watch?v=IYQgtu9TM74) - A brief tutorial covering State Management and Navigation by Thad Carnevalli. (inglês) | ||
946 | -- [Build a To-do List App from scratch using Flutter and GetX™](https://www.youtube.com/watch?v=EcnqFasHf18) - UI + State Management + Storage video by Thad Carnevalli. (inglês) | ||
947 | -- [GetX™ Flutter Firebase Auth Example](https://medium.com/@jeffmcmorris/getx-flutter-firebase-auth-example-b383c1dd1de2) - Article by Jeff McMorris. (inglês) |
getx/counter-app-gif.gif
deleted
100644 → 0

145 KB
getx/get.png
deleted
100644 → 0

115 KB
getx/getx.png
deleted
100644 → 0

125 KB
getx/lib/get.dart
deleted
100644 → 0
1 | -/// GetX is an extra-light and powerful multiplatform framework. | ||
2 | -/// It combines high performance state management, intelligent dependency | ||
3 | -/// injection, and route management in a quick and practical way. | ||
4 | -library get; | ||
5 | - | ||
6 | -export 'package:get_core/get_core.dart'; | ||
7 | -export 'package:get_state_manager/get_state_manager.dart'; | ||
8 | -export 'package:get_instance/get_instance.dart'; | ||
9 | -export 'package:get_navigation/get_navigation.dart'; | ||
10 | -export 'package:get_utils/get_utils.dart'; | ||
11 | -export 'package:get_rx/get_rx.dart'; | ||
12 | -export 'package:get_test/get_test.dart'; |
getx/lib/instance_manager.dart
deleted
100644 → 0
getx/lib/route_manager.dart
deleted
100644 → 0
getx/lib/state_manager.dart
deleted
100644 → 0
getx/lib/utils.dart
deleted
100644 → 0
getx/logo-no-background.png
deleted
100644 → 0

73.8 KB
lib/get.dart
0 → 100644
1 | +/// GetX is an extra-light and powerful multiplatform framework. | ||
2 | +/// It combines high performance state management, intelligent dependency | ||
3 | +/// injection, and route management in a quick and practical way. | ||
4 | +library get; | ||
5 | + | ||
6 | +export 'get_core/get_core.dart'; | ||
7 | +export 'get_instance/get_instance.dart'; | ||
8 | +export 'get_navigation/get_navigation.dart'; | ||
9 | +export 'get_rx/get_rx.dart'; | ||
10 | +export 'get_state_manager/get_state_manager.dart'; | ||
11 | +export 'get_utils/get_utils.dart'; |
lib/get_core/get_core.dart
0 → 100644
lib/get_core/src/get_interface.dart
0 → 100644
1 | +import 'log.dart'; | ||
2 | +import 'smart_management.dart'; | ||
3 | + | ||
4 | +/// GetInterface allows any auxiliary package to be merged into the "Get" | ||
5 | +/// class through extensions | ||
6 | +abstract class GetInterface { | ||
7 | + SmartManagement smartManagement = SmartManagement.full; | ||
8 | + String reference; | ||
9 | + bool isLogEnable = true; | ||
10 | + LogWriterCallback log = defaultLogWriterCallback; | ||
11 | +} |
lib/get_core/src/get_main.dart
0 → 100644
1 | +import 'get_interface.dart'; | ||
2 | + | ||
3 | +///Use to instead of Navigator.push, off instead of Navigator.pushReplacement, | ||
4 | +///offAll instead of Navigator.pushAndRemoveUntil. For named routes just | ||
5 | +///add "named" after them. Example: toNamed, offNamed, and AllNamed. | ||
6 | +///To return to the previous screen, use back(). | ||
7 | +///No need to pass any context to Get, just put the name of the route inside | ||
8 | +///the parentheses and the magic will occur. | ||
9 | +class _GetImpl extends GetInterface {} | ||
10 | + | ||
11 | +// ignore: non_constant_identifier_names | ||
12 | +final Get = _GetImpl(); |
lib/get_core/src/log.dart
0 → 100644
1 | +import 'dart:developer' as developer; | ||
2 | +import 'get_main.dart'; | ||
3 | + | ||
4 | +///Voidcallback from logs | ||
5 | +typedef LogWriterCallback = void Function(String text, {bool isError}); | ||
6 | + | ||
7 | +/// default logger from GetX | ||
8 | +void defaultLogWriterCallback(String value, {bool isError = false}) { | ||
9 | + if (isError || Get.isLogEnable) developer.log(value, name: 'GETX'); | ||
10 | +} |
lib/get_core/src/smart_management.dart
0 → 100644
1 | +/// GetX by default disposes unused controllers from memory, | ||
2 | +/// Through different behaviors. | ||
3 | +/// SmartManagement.full | ||
4 | +/// [SmartManagement.full] is the default one. Dispose classes that are | ||
5 | +/// not being used and were not set to be permanent. In the majority | ||
6 | +/// of the cases you will want to keep this config untouched. | ||
7 | +/// If you new to GetX then don't change this. | ||
8 | +/// [SmartManagement.onlyBuilders] only controllers started in init: | ||
9 | +/// or loaded into a Binding with Get.lazyPut() will be disposed. If you use | ||
10 | +/// Get.put() or Get.putAsync() or any other approach, SmartManagement | ||
11 | +/// will not have permissions to exclude this dependency. With the default | ||
12 | +/// behavior, even widgets instantiated with "Get.put" will be removed, | ||
13 | +/// unlike SmartManagement.onlyBuilders. | ||
14 | +/// [SmartManagement.keepFactory]Just like SmartManagement.full, | ||
15 | +/// it will remove it's dependencies when it's not being used anymore. | ||
16 | +/// However, it will keep their factory, which means it will recreate | ||
17 | +/// the dependency if you need that instance again. | ||
18 | +enum SmartManagement { | ||
19 | + full, | ||
20 | + onlyBuilder, | ||
21 | + keepFactory, | ||
22 | +} |
lib/get_instance/get_instance.dart
0 → 100644
lib/get_instance/src/bindings_interface.dart
0 → 100644
1 | +import 'get_instance.dart'; | ||
2 | + | ||
3 | +/// [Bindings] should be extended or implemented. | ||
4 | +/// When using [GetMaterialApp], all [GetPage]s and navigation | ||
5 | +/// methods (like Get.to()) have a [binding] property that takes an | ||
6 | +/// instance of Bindings to manage the | ||
7 | +/// dependencies() (via [Get.put()]) for the Route you are opening. | ||
8 | +// ignore: one_member_abstracts | ||
9 | +abstract class Bindings { | ||
10 | + void dependencies(); | ||
11 | +} | ||
12 | + | ||
13 | +/// Simplifies Bindings generation from a single callback. | ||
14 | +/// To avoid the creation of a custom Binding instance per route. | ||
15 | +/// | ||
16 | +/// Example: | ||
17 | +/// ``` | ||
18 | +/// GetPage( | ||
19 | +/// name: '/', | ||
20 | +/// page: () => Home(), | ||
21 | +/// // This might cause you an error. | ||
22 | +/// // binding: BindingsBuilder(() => Get.put(HomeController())), | ||
23 | +/// binding: BindingsBuilder(() { Get.put(HomeController(); })), | ||
24 | +/// // Using .lazyPut() works fine. | ||
25 | +/// // binding: BindingsBuilder(() => Get.lazyPut(() => HomeController())), | ||
26 | +/// ), | ||
27 | +/// ``` | ||
28 | +class BindingsBuilder<T> extends Bindings { | ||
29 | + /// Register your dependencies in the [builder] callback. | ||
30 | + final BindingBuilderCallback builder; | ||
31 | + | ||
32 | + /// Shortcut to register 1 Controller with Get.put(), | ||
33 | + /// Prevents the issue of the fat arrow function with the constructor. | ||
34 | + /// BindingsBuilder(() => Get.put(HomeController())), | ||
35 | + /// | ||
36 | + /// Sample: | ||
37 | + /// ``` | ||
38 | + /// GetPage( | ||
39 | + /// name: '/', | ||
40 | + /// page: () => Home(), | ||
41 | + /// binding: BindingsBuilder.put(() => HomeController()), | ||
42 | + /// ), | ||
43 | + /// ``` | ||
44 | + factory BindingsBuilder.put(InstanceBuilderCallback<T> builder, | ||
45 | + {String tag, bool permanent = false}) { | ||
46 | + return BindingsBuilder(() => GetInstance() | ||
47 | + .put<T>(null, tag: tag, permanent: permanent, builder: builder)); | ||
48 | + } | ||
49 | + | ||
50 | + /// WARNING: don't use `()=> Get.put(Controller())`, | ||
51 | + /// if only passing 1 callback use `BindingsBuilder.put(Controller())` | ||
52 | + /// or `BindingsBuilder(()=> Get.lazyPut(Controller()))` | ||
53 | + BindingsBuilder(this.builder); | ||
54 | + | ||
55 | + @override | ||
56 | + void dependencies() { | ||
57 | + builder(); | ||
58 | + } | ||
59 | +} | ||
60 | + | ||
61 | +// abstract class INavigation {} | ||
62 | +// typedef Snack = Function(); | ||
63 | +// typedef Modal = Function(); | ||
64 | +// typedef Route = Function(); | ||
65 | +typedef BindingBuilderCallback = void Function(); |
lib/get_instance/src/extension_instance.dart
0 → 100644
1 | +import '../../get_core/src/get_interface.dart'; | ||
2 | + | ||
3 | +import 'get_instance.dart'; | ||
4 | + | ||
5 | +extension Inst on GetInterface { | ||
6 | + /// Creates a new Instance<S> lazily from the [<S>builder()] callback. | ||
7 | + /// | ||
8 | + /// The first time you call [Get.find()], the [builder()] callback will create | ||
9 | + /// the Instance and persisted as a Singleton (like you would use | ||
10 | + /// [Get.put()]). | ||
11 | + /// | ||
12 | + /// Using [Get.smartManagement] as [SmartManagement.keepFactory] has | ||
13 | + /// the same outcome | ||
14 | + /// as using [fenix:true] : | ||
15 | + /// The internal register of [builder()] will remain in memory to recreate | ||
16 | + /// the Instance if the Instance has been removed with [Get.delete()]. | ||
17 | + /// Therefore, future calls to [Get.find()] will return the same Instance. | ||
18 | + /// | ||
19 | + /// If you need to make use of GetxController's life-cycle | ||
20 | + /// ([onInit(), onStart(), onClose()]) | ||
21 | + /// [fenix] is a great choice to mix with [GetBuilder()] and [GetX()] widgets, | ||
22 | + /// and/or [GetMaterialApp] Navigation. | ||
23 | + /// | ||
24 | + /// You could use [Get.lazyPut(fenix:true)] in your app's [main()] instead of | ||
25 | + /// [Bindings()] for each [GetPage]. | ||
26 | + /// And the memory management will be similar. | ||
27 | + /// | ||
28 | + /// Subsequent calls to [Get.lazyPut()] with the same parameters | ||
29 | + /// (<[S]> and optionally [tag] will **not** override the original). | ||
30 | + void lazyPut<S>(InstanceBuilderCallback<S> builder, | ||
31 | + {String tag, bool fenix = false}) { | ||
32 | + GetInstance().lazyPut<S>(builder, tag: tag, fenix: fenix); | ||
33 | + } | ||
34 | + | ||
35 | + /// async version of [Get.put()]. | ||
36 | + /// Awaits for the resolution of the Future from [builder()] parameter and | ||
37 | + /// stores the Instance returned. | ||
38 | + Future<S> putAsync<S>(AsyncInstanceBuilderCallback<S> builder, | ||
39 | + {String tag, bool permanent = false}) async => | ||
40 | + GetInstance().putAsync<S>(builder, tag: tag, permanent: permanent); | ||
41 | + | ||
42 | + /// Creates a new Class Instance [S] from the builder callback[S]. | ||
43 | + /// Every time [find]<[S]>() is used, it calls the builder method to generate | ||
44 | + /// a new Instance [S]. | ||
45 | + /// It also registers each [instance.onClose()] with the current | ||
46 | + /// Route [GetConfig.currentRoute] to keep the lifecycle active. | ||
47 | + /// Is important to know that the instances created are only stored per Route. | ||
48 | + /// So, if you call `Get.delete<T>()` the "instance factory" used in this | ||
49 | + /// method ([Get.create<T>()]) will be removed, but NOT the instances | ||
50 | + /// already created by it. | ||
51 | + /// Uses `tag` as the other methods. | ||
52 | + /// | ||
53 | + /// Example: | ||
54 | + /// | ||
55 | + /// ```create(() => Repl()); | ||
56 | + /// Repl a = find(); | ||
57 | + /// Repl b = find(); | ||
58 | + /// print(a==b); (false)``` | ||
59 | + void create<S>(InstanceBuilderCallback<S> builder, | ||
60 | + {String tag, bool permanent = true}) => | ||
61 | + GetInstance().create<S>(builder, tag: tag, permanent: permanent); | ||
62 | + | ||
63 | + /// Finds a Instance of the required Class <[S]>(or [tag]) | ||
64 | + /// In the case of using [Get.create()], it will generate an Instance | ||
65 | + /// each time you call [Get.find()]. | ||
66 | + S find<S>({String tag}) => GetInstance().find<S>(tag: tag); | ||
67 | + | ||
68 | + /// Injects an [Instance<S>] in memory. | ||
69 | + /// | ||
70 | + /// No need to define the generic type <[S]> as it's inferred | ||
71 | + /// from the [dependency] parameter. | ||
72 | + /// | ||
73 | + /// - [dependency] The Instance to be injected. | ||
74 | + /// - [tag] optionally, use a [tag] as an "id" to create multiple records | ||
75 | + /// of the same Type<[S]> the [tag] does **not** conflict with the same tags | ||
76 | + /// used by other [dependencies] Types. | ||
77 | + /// - [permanent] keeps the Instance in memory and persist it, | ||
78 | + /// not following [Get.smartManagement] | ||
79 | + /// rules. Although, can be removed by [GetInstance.reset()] | ||
80 | + /// and [Get.delete()] | ||
81 | + /// - [builder] If defined, the [dependency] must be returned from here | ||
82 | + S put<S>(S dependency, | ||
83 | + {String tag, | ||
84 | + bool permanent = false, | ||
85 | + InstanceBuilderCallback<S> builder}) => | ||
86 | + GetInstance() | ||
87 | + .put<S>(dependency, tag: tag, permanent: permanent, builder: builder); | ||
88 | + | ||
89 | + /// Clears all registered instances (and/or tags). | ||
90 | + /// Even the persistent ones. | ||
91 | + /// | ||
92 | + /// - [clearFactory] clears the callbacks registered by [Get.lazyPut()] | ||
93 | + /// - [clearRouteBindings] clears Instances associated with Routes when using | ||
94 | + /// [GetMaterialApp]. | ||
95 | + bool reset({bool clearFactory = true, bool clearRouteBindings = true}) => | ||
96 | + GetInstance().reset( | ||
97 | + clearFactory: clearFactory, clearRouteBindings: clearRouteBindings); | ||
98 | + | ||
99 | + /// Deletes the Instance<[S]>, cleaning the memory and closes any open | ||
100 | + /// controllers ([DisposableInterface]). | ||
101 | + /// | ||
102 | + /// - [tag] Optional "tag" used to register the Instance | ||
103 | + /// - [force] Will delete an Instance even if marked as [permanent]. | ||
104 | + Future<bool> delete<S>({String tag, bool force = false}) async => | ||
105 | + GetInstance().delete<S>(tag: tag, force: force); | ||
106 | + | ||
107 | + /// Checks if a Class Instance<[S]> (or [tag]) is registered in memory. | ||
108 | + /// - [tag] optional, if you use a [tag] to register the Instance. | ||
109 | + bool isRegistered<S>({String tag}) => GetInstance().isRegistered<S>(tag: tag); | ||
110 | + | ||
111 | + /// Checks if an Instance<[S]> (or [tag]) returned from a factory builder | ||
112 | + /// [Get.lazyPut()], is registered in memory. | ||
113 | + /// - [tag] optional, if you use a [tag] to register the Instance. | ||
114 | + bool isPrepared<S>({String tag}) => GetInstance().isPrepared<S>(tag: tag); | ||
115 | +} |
lib/get_instance/src/get_instance.dart
0 → 100644
1 | +import 'dart:async'; | ||
2 | +import 'dart:collection'; | ||
3 | +import '../../get_core/get_core.dart'; | ||
4 | + | ||
5 | +import 'lifecycle.dart'; | ||
6 | + | ||
7 | +class GetInstance { | ||
8 | + factory GetInstance() => _getInstance ??= GetInstance._(); | ||
9 | + | ||
10 | + const GetInstance._(); | ||
11 | + | ||
12 | + static GetInstance _getInstance; | ||
13 | + | ||
14 | + /// Holds references to every registered Instance when using | ||
15 | + /// [Get.put()] | ||
16 | + static final Map<String, _InstanceBuilderFactory> _singl = {}; | ||
17 | + | ||
18 | + /// Holds a reference to every registered callback when using | ||
19 | + /// [Get.lazyPut()] | ||
20 | + static final Map<String, _Lazy> _factory = {}; | ||
21 | + | ||
22 | + /// Holds a reference to [Get.reference] when the Instance was | ||
23 | + /// created to manage the memory. | ||
24 | + static final Map<String, String> _routesKey = {}; | ||
25 | + | ||
26 | + /// Stores the onClose() references of instances created with [Get.create()] | ||
27 | + /// using the [Get.reference]. | ||
28 | + /// Experimental feature to keep the lifecycle and memory management with | ||
29 | + /// non-singleton instances. | ||
30 | + static final Map<String, HashSet<Function>> _routesByCreate = {}; | ||
31 | + | ||
32 | + /// Creates a new Instance<S> lazily from the [<S>builder()] callback. | ||
33 | + /// | ||
34 | + /// The first time you call [Get.find()], the [builder()] callback will create | ||
35 | + /// the Instance and persisted as a Singleton (like you would | ||
36 | + /// use [Get.put()]). | ||
37 | + /// | ||
38 | + /// Using [Get.smartManagement] as [SmartManagement.keepFactory] has | ||
39 | + /// the same outcome as using [fenix:true] : | ||
40 | + /// The internal register of [builder()] will remain in memory to recreate | ||
41 | + /// the Instance if the Instance has been removed with [Get.delete()]. | ||
42 | + /// Therefore, future calls to [Get.find()] will return the same Instance. | ||
43 | + /// | ||
44 | + /// If you need to make use of GetxController's life-cycle | ||
45 | + /// ([onInit(), onStart(), onClose()]) [fenix] is a great choice to mix with | ||
46 | + /// [GetBuilder()] and [GetX()] widgets, and/or [GetMaterialApp] Navigation. | ||
47 | + /// | ||
48 | + /// You could use [Get.lazyPut(fenix:true)] in your app's [main()] instead | ||
49 | + /// of [Bindings()] for each [GetPage]. | ||
50 | + /// And the memory management will be similar. | ||
51 | + /// | ||
52 | + /// Subsequent calls to [Get.lazyPut()] with the same parameters | ||
53 | + /// (<[S]> and optionally [tag] will **not** override the original). | ||
54 | + void lazyPut<S>( | ||
55 | + InstanceBuilderCallback<S> builder, { | ||
56 | + String tag, | ||
57 | + bool fenix = false, | ||
58 | + }) { | ||
59 | + final key = _getKey(S, tag); | ||
60 | + _factory.putIfAbsent(key, () => _Lazy(builder, fenix)); | ||
61 | + } | ||
62 | + | ||
63 | + /// async version of [Get.put()]. | ||
64 | + /// Awaits for the resolution of the Future from [builder()] parameter and | ||
65 | + /// stores the Instance returned. | ||
66 | + Future<S> putAsync<S>( | ||
67 | + AsyncInstanceBuilderCallback<S> builder, { | ||
68 | + String tag, | ||
69 | + bool permanent = false, | ||
70 | + }) async { | ||
71 | + return put<S>(await builder(), tag: tag, permanent: permanent); | ||
72 | + } | ||
73 | + | ||
74 | + /// Injects an instance <[S]> in memory to be globally accessible. | ||
75 | + /// | ||
76 | + /// No need to define the generic type <[S]> as it's inferred from | ||
77 | + /// the [dependency] | ||
78 | + /// | ||
79 | + /// - [dependency] The Instance to be injected. | ||
80 | + /// - [tag] optionally, use a [tag] as an "id" to create multiple records of | ||
81 | + /// the same Type<[S]> | ||
82 | + /// - [permanent] keeps the Instance in memory, not following | ||
83 | + /// [Get.smartManagement] rules. | ||
84 | + S put<S>( | ||
85 | + S dependency, { | ||
86 | + String tag, | ||
87 | + bool permanent = false, | ||
88 | + InstanceBuilderCallback<S> builder, | ||
89 | + }) { | ||
90 | + _insert( | ||
91 | + isSingleton: true, | ||
92 | + name: tag, | ||
93 | + permanent: permanent, | ||
94 | + builder: builder ?? (() => dependency)); | ||
95 | + return find<S>(tag: tag); | ||
96 | + } | ||
97 | + | ||
98 | + /// Creates a new Class Instance [S] from the builder callback[S]. | ||
99 | + /// Every time [find]<[S]>() is used, it calls the builder method to generate | ||
100 | + /// a new Instance [S]. | ||
101 | + /// It also registers each [instance.onClose()] with the current | ||
102 | + /// Route [Get.reference] to keep the lifecycle active. | ||
103 | + /// Is important to know that the instances created are only stored per Route. | ||
104 | + /// So, if you call `Get.delete<T>()` the "instance factory" used in this | ||
105 | + /// method ([Get.create<T>()]) will be removed, but NOT the instances | ||
106 | + /// already created by it. | ||
107 | + /// | ||
108 | + /// Example: | ||
109 | + /// | ||
110 | + /// ```create(() => Repl()); | ||
111 | + /// Repl a = find(); | ||
112 | + /// Repl b = find(); | ||
113 | + /// print(a==b); (false)``` | ||
114 | + void create<S>( | ||
115 | + InstanceBuilderCallback<S> builder, { | ||
116 | + String tag, | ||
117 | + bool permanent = true, | ||
118 | + }) { | ||
119 | + _insert( | ||
120 | + isSingleton: false, name: tag, builder: builder, permanent: permanent); | ||
121 | + } | ||
122 | + | ||
123 | + /// Injects the Instance [S] builder into the [_singleton] HashMap. | ||
124 | + void _insert<S>({ | ||
125 | + bool isSingleton, | ||
126 | + String name, | ||
127 | + bool permanent = false, | ||
128 | + InstanceBuilderCallback<S> builder, | ||
129 | + }) { | ||
130 | + assert(builder != null); | ||
131 | + final key = _getKey(S, name); | ||
132 | + _singl.putIfAbsent( | ||
133 | + key, | ||
134 | + () => | ||
135 | + _InstanceBuilderFactory<S>(isSingleton, builder, permanent, false)); | ||
136 | + } | ||
137 | + | ||
138 | + /// Clears from memory registered Instances associated with [routeName] when | ||
139 | + /// using [Get.smartManagement] as [SmartManagement.full] or | ||
140 | + /// [SmartManagement.keepFactory] | ||
141 | + /// Meant for internal usage of [GetPageRoute] and [GetDialogRoute] | ||
142 | + void removeDependencyByRoute(String routeName) { | ||
143 | + final keysToRemove = <String>[]; | ||
144 | + _routesKey.forEach((key, value) { | ||
145 | + if (value == routeName) { | ||
146 | + keysToRemove.add(key); | ||
147 | + } | ||
148 | + }); | ||
149 | + | ||
150 | + /// Removes [Get.create()] instances registered in [routeName]. | ||
151 | + if (_routesByCreate.containsKey(routeName)) { | ||
152 | + for (final onClose in _routesByCreate[routeName]) { | ||
153 | + // assure the [DisposableInterface] instance holding a reference | ||
154 | + // to [onClose()] wasn't disposed. | ||
155 | + if (onClose != null) { | ||
156 | + onClose(); | ||
157 | + } | ||
158 | + } | ||
159 | + _routesByCreate[routeName].clear(); | ||
160 | + _routesByCreate.remove(routeName); | ||
161 | + } | ||
162 | + | ||
163 | + for (final element in keysToRemove) { | ||
164 | + delete(key: element); | ||
165 | + } | ||
166 | + | ||
167 | + for (final element in keysToRemove) { | ||
168 | + _routesKey?.remove(element); | ||
169 | + } | ||
170 | + keysToRemove.clear(); | ||
171 | + } | ||
172 | + | ||
173 | + /// Initializes the dependencies for a Class Instance [S] (or tag), | ||
174 | + /// If its a Controller, it starts the lifecycle process. | ||
175 | + /// Optionally associating the current Route to the lifetime of the instance, | ||
176 | + /// if [Get.smartManagement] is marked as [SmartManagement.full] or | ||
177 | + /// [Get.keepFactory] | ||
178 | + /// Only flags `isInit` if it's using `Get.create()` | ||
179 | + /// (not for Singletons access). | ||
180 | + /// Returns the instance if not initialized, required for Get.create() to | ||
181 | + /// work properly. | ||
182 | + S _initDependencies<S>({String name}) { | ||
183 | + final key = _getKey(S, name); | ||
184 | + final isInit = _singl[key].isInit; | ||
185 | + S i; | ||
186 | + if (!isInit) { | ||
187 | + i = _startController<S>(tag: name); | ||
188 | + if (_singl[key].isSingleton) { | ||
189 | + _singl[key].isInit = true; | ||
190 | + if (Get.smartManagement != SmartManagement.onlyBuilder) { | ||
191 | + _registerRouteInstance<S>(tag: name); | ||
192 | + } | ||
193 | + } | ||
194 | + } | ||
195 | + return i; | ||
196 | + } | ||
197 | + | ||
198 | + /// Links a Class instance [S] (or [tag]) to the current route. | ||
199 | + /// Requires usage of [GetMaterialApp]. | ||
200 | + void _registerRouteInstance<S>({String tag}) { | ||
201 | + _routesKey.putIfAbsent(_getKey(S, tag), () => Get.reference); | ||
202 | + } | ||
203 | + | ||
204 | + /// Finds and returns a Instance<[S]> (or [tag]) without further processing. | ||
205 | + S findByType<S>(Type type, {String tag}) { | ||
206 | + final key = _getKey(type, tag); | ||
207 | + return _singl[key].getDependency() as S; | ||
208 | + } | ||
209 | + | ||
210 | + /// Initializes the controller | ||
211 | + S _startController<S>({String tag}) { | ||
212 | + final key = _getKey(S, tag); | ||
213 | + final i = _singl[key].getDependency() as S; | ||
214 | + if (i is GetLifeCycle) { | ||
215 | + if (i.onStart != null) { | ||
216 | + i.onStart(); | ||
217 | + Get.log('"$key" has been initialized'); | ||
218 | + } | ||
219 | + if (!_singl[key].isSingleton && i.onClose != null) { | ||
220 | + _routesByCreate[Get.reference] ??= HashSet<Function>(); | ||
221 | + _routesByCreate[Get.reference].add(i.onClose); | ||
222 | + } | ||
223 | + } | ||
224 | + return i; | ||
225 | + } | ||
226 | + | ||
227 | + S putOrFind<S>(InstanceBuilderCallback<S> dep, {String tag}) { | ||
228 | + final key = _getKey(S, tag); | ||
229 | + | ||
230 | + if (_singl.containsKey(key)) { | ||
231 | + return _singl[key].getDependency() as S; | ||
232 | + } else { | ||
233 | + if (_factory.containsKey(key)) { | ||
234 | + final _value = put<S>((_factory[key].builder() as S), tag: tag); | ||
235 | + | ||
236 | + if (Get.smartManagement != SmartManagement.keepFactory) { | ||
237 | + if (!_factory[key].fenix) { | ||
238 | + _factory.remove(key); | ||
239 | + } | ||
240 | + } | ||
241 | + return _value; | ||
242 | + } | ||
243 | + | ||
244 | + return GetInstance().put(dep(), tag: tag); | ||
245 | + } | ||
246 | + } | ||
247 | + | ||
248 | + /// Finds the registered type <[S]> (or [tag]) | ||
249 | + /// In case of using Get.[create] to register a type <[S]> or [tag], | ||
250 | + /// it will create an instance each time you call [find]. | ||
251 | + /// If the registered type <[S]> (or [tag]) is a Controller, | ||
252 | + /// it will initialize it's lifecycle. | ||
253 | + S find<S>({String tag}) { | ||
254 | + final key = _getKey(S, tag); | ||
255 | + if (isRegistered<S>(tag: tag)) { | ||
256 | + if (_singl[key] == null) { | ||
257 | + if (tag == null) { | ||
258 | + throw 'Class "$S" is not registered'; | ||
259 | + } else { | ||
260 | + throw 'Class "$S" with tag "$tag" is not registered'; | ||
261 | + } | ||
262 | + } | ||
263 | + | ||
264 | + /// although dirty solution, the lifecycle starts inside | ||
265 | + /// `initDependencies`, so we have to return the instance from there | ||
266 | + /// to make it compatible with `Get.create()`. | ||
267 | + final i = _initDependencies<S>(name: tag); | ||
268 | + return i ?? _singl[key].getDependency() as S; | ||
269 | + } else { | ||
270 | + if (!_factory.containsKey(key)) { | ||
271 | + // ignore: lines_longer_than_80_chars | ||
272 | + throw '"$S" not found. You need to call "Get.put($S())" or "Get.lazyPut(()=>$S())"'; | ||
273 | + } | ||
274 | + | ||
275 | + Get.log('Lazy instance "$S" created'); | ||
276 | + final _value = put<S>(_factory[key].builder() as S, tag: tag); | ||
277 | + _initDependencies<S>(name: tag); | ||
278 | + | ||
279 | + if (Get.smartManagement != SmartManagement.keepFactory && | ||
280 | + !_factory[key].fenix) { | ||
281 | + _factory.remove(key); | ||
282 | + } | ||
283 | + | ||
284 | + return _value; | ||
285 | + } | ||
286 | + } | ||
287 | + | ||
288 | + /// Generates the key based on [type] (and optionally a [name]) | ||
289 | + /// to register an Instance Builder in the hashmap. | ||
290 | + String _getKey(Type type, String name) { | ||
291 | + return name == null ? type.toString() : type.toString() + name; | ||
292 | + } | ||
293 | + | ||
294 | + /// Clears all registered instances (and/or tags). | ||
295 | + /// Even the persistent ones. | ||
296 | + /// | ||
297 | + /// [clearFactory] clears the callbacks registered by [lazyPut] | ||
298 | + /// [clearRouteBindings] clears Instances associated with routes. | ||
299 | + /// | ||
300 | + bool reset({bool clearFactory = true, bool clearRouteBindings = true}) { | ||
301 | + if (clearFactory) _factory.clear(); | ||
302 | + if (clearRouteBindings) _routesKey.clear(); | ||
303 | + _singl.clear(); | ||
304 | + return true; | ||
305 | + } | ||
306 | + | ||
307 | + /// Delete registered Class Instance [S] (or [tag]) and, closes any open | ||
308 | + /// controllers [DisposableInterface], cleans up the memory | ||
309 | + /// | ||
310 | + /// /// Deletes the Instance<[S]>, cleaning the memory. | ||
311 | + // /// | ||
312 | + // /// - [tag] Optional "tag" used to register the Instance | ||
313 | + // /// - [key] For internal usage, is the processed key used to register | ||
314 | + // /// the Instance. **don't use** it unless you know what you are doing. | ||
315 | + | ||
316 | + /// Deletes the Instance<[S]>, cleaning the memory and closes any open | ||
317 | + /// controllers ([DisposableInterface]). | ||
318 | + /// | ||
319 | + /// - [tag] Optional "tag" used to register the Instance | ||
320 | + /// - [key] For internal usage, is the processed key used to register | ||
321 | + /// the Instance. **don't use** it unless you know what you are doing. | ||
322 | + /// - [force] Will delete an Instance even if marked as [permanent]. | ||
323 | + bool delete<S>({String tag, String key, bool force = false}) { | ||
324 | + // return _queue.secure<bool>(() { | ||
325 | + return _delete<S>(tag: tag, key: key, force: force); | ||
326 | + // }); | ||
327 | + } | ||
328 | + | ||
329 | + bool _delete<S>({String tag, String key, bool force = false}) { | ||
330 | + final newKey = key ?? _getKey(S, tag); | ||
331 | + | ||
332 | + if (!_singl.containsKey(newKey)) { | ||
333 | + Get.log('Instance "$newKey" already removed.', isError: true); | ||
334 | + return false; | ||
335 | + } | ||
336 | + | ||
337 | + final builder = _singl[newKey]; | ||
338 | + if (builder.permanent && !force) { | ||
339 | + Get.log( | ||
340 | + // ignore: lines_longer_than_80_chars | ||
341 | + '"$newKey" has been marked as permanent, SmartManagement is not authorized to delete it.', | ||
342 | + isError: true, | ||
343 | + ); | ||
344 | + return false; | ||
345 | + } | ||
346 | + final i = builder.dependency; | ||
347 | + | ||
348 | + if (i is GetxServiceMixin && !force) { | ||
349 | + return false; | ||
350 | + } | ||
351 | + if (i is GetLifeCycle) { | ||
352 | + i.onClose(); | ||
353 | + Get.log('"$newKey" onClose() called'); | ||
354 | + } | ||
355 | + | ||
356 | + _singl.removeWhere((oldKey, value) => (oldKey == newKey)); | ||
357 | + if (_singl.containsKey(newKey)) { | ||
358 | + Get.log('Error removing object "$newKey"', isError: true); | ||
359 | + } else { | ||
360 | + Get.log('"$newKey" deleted from memory'); | ||
361 | + } | ||
362 | + // _routesKey?.remove(key); | ||
363 | + return true; | ||
364 | + } | ||
365 | + | ||
366 | + /// Check if a Class Instance<[S]> (or [tag]) is registered in memory. | ||
367 | + /// - [tag] is optional, if you used a [tag] to register the Instance. | ||
368 | + bool isRegistered<S>({String tag}) => _singl.containsKey(_getKey(S, tag)); | ||
369 | + | ||
370 | + /// Checks if a lazy factory callback ([Get.lazyPut()] that returns an | ||
371 | + /// Instance<[S]> is registered in memory. | ||
372 | + /// - [tag] is optional, if you used a [tag] to register the lazy Instance. | ||
373 | + bool isPrepared<S>({String tag}) => _factory.containsKey(_getKey(S, tag)); | ||
374 | +} | ||
375 | + | ||
376 | +typedef InstanceBuilderCallback<S> = S Function(); | ||
377 | + | ||
378 | +typedef AsyncInstanceBuilderCallback<S> = Future<S> Function(); | ||
379 | + | ||
380 | +/// Internal class to register instances with Get.[put]<[S]>(). | ||
381 | +class _InstanceBuilderFactory<S> { | ||
382 | + /// Marks the Builder as a single instance. | ||
383 | + /// For reusing [dependency] instead of [builderFunc] | ||
384 | + bool isSingleton; | ||
385 | + | ||
386 | + /// Stores the actual object instance when [isSingleton]=true. | ||
387 | + S dependency; | ||
388 | + | ||
389 | + /// Generates (and regenerates) the instance when [isSingleton]=false. | ||
390 | + /// Usually used by factory methods | ||
391 | + InstanceBuilderCallback<S> builderFunc; | ||
392 | + | ||
393 | + /// Flag to persist the instance in memory, | ||
394 | + /// without considering [Get.smartManagement] | ||
395 | + bool permanent = false; | ||
396 | + | ||
397 | + bool isInit = false; | ||
398 | + | ||
399 | + _InstanceBuilderFactory( | ||
400 | + this.isSingleton, | ||
401 | + this.builderFunc, | ||
402 | + this.permanent, | ||
403 | + this.isInit, | ||
404 | + ); | ||
405 | + | ||
406 | + /// Gets the actual instance by it's [builderFunc] or the persisted instance. | ||
407 | + S getDependency() { | ||
408 | + return isSingleton ? dependency ??= builderFunc() : builderFunc(); | ||
409 | + } | ||
410 | +} | ||
411 | + | ||
412 | +/// Internal class to register a future instance with [lazyPut], | ||
413 | +/// keeps a reference to the callback to be called. | ||
414 | +class _Lazy { | ||
415 | + bool fenix; | ||
416 | + InstanceBuilderCallback builder; | ||
417 | + | ||
418 | + _Lazy(this.builder, this.fenix); | ||
419 | +} |
lib/get_instance/src/lifecycle.dart
0 → 100644
1 | +/// Special callable class to keep the contract of a regular method, and avoid | ||
2 | +/// overrides if you extend the class that uses it, as Dart has no final | ||
3 | +/// methods. | ||
4 | +/// Used in [DisposableInterface] to avoid the danger of overriding onStart. | ||
5 | +/// | ||
6 | +class _InternalFinalCallback<T> { | ||
7 | + T Function() callback; | ||
8 | + | ||
9 | + _InternalFinalCallback(); | ||
10 | + | ||
11 | + T call() => callback.call(); | ||
12 | +} | ||
13 | + | ||
14 | +abstract class GetLifeCycle { | ||
15 | + /// Called at the exact moment the widget is allocated in memory. | ||
16 | + /// It uses an internal "callable" type, to avoid any @overrides in subclases. | ||
17 | + /// This method should be internal and is required to define the | ||
18 | + /// lifetime cycle of the subclass. | ||
19 | + final onStart = _InternalFinalCallback<void>(); | ||
20 | + | ||
21 | + /// Called immediately after the widget is allocated in memory. | ||
22 | + /// You might use this to initialize something for the controller. | ||
23 | + void onInit() {} | ||
24 | + | ||
25 | + /// Called 1 frame after onInit(). It is the perfect place to enter | ||
26 | + /// navigation events, like snackbar, dialogs, or a new route, or | ||
27 | + /// async request. | ||
28 | + void onReady() {} | ||
29 | + | ||
30 | + /// Called before [onDelete] method. [onClose] might be used to | ||
31 | + /// dispose resources used by the controller. Like closing events, | ||
32 | + /// or streams before the controller is destroyed. | ||
33 | + /// Or dispose objects that can potentially create some memory leaks, | ||
34 | + /// like TextEditingControllers, AnimationControllers. | ||
35 | + /// Might be useful as well to persist some data on disk. | ||
36 | + void onClose() {} | ||
37 | +} | ||
38 | + | ||
39 | +/// Allow track difference between GetxServices and GetxControllers | ||
40 | +mixin GetxServiceMixin {} |
lib/get_navigation/get_navigation.dart
0 → 100644
1 | +library get_navigation; | ||
2 | + | ||
3 | +export 'src/bottomsheet/bottomsheet.dart'; | ||
4 | +export 'src/extension_navigation.dart'; | ||
5 | +export 'src/root/root_widget.dart'; | ||
6 | +export 'src/routes/custom_transition.dart'; | ||
7 | +export 'src/routes/default_route.dart'; | ||
8 | +export 'src/routes/default_route.dart'; | ||
9 | +export 'src/routes/get_route.dart'; | ||
10 | +export 'src/routes/observers/route_observer.dart'; | ||
11 | +export 'src/routes/transitions_type.dart'; | ||
12 | +export 'src/snackbar/snack.dart'; | ||
13 | +export 'src/snackbar/snack_route.dart'; |
1 | +import 'package:flutter/material.dart'; | ||
2 | + | ||
3 | +class GetModalBottomSheetRoute<T> extends PopupRoute<T> { | ||
4 | + GetModalBottomSheetRoute({ | ||
5 | + this.builder, | ||
6 | + this.theme, | ||
7 | + this.barrierLabel, | ||
8 | + this.backgroundColor, | ||
9 | + this.isPersistent, | ||
10 | + this.elevation, | ||
11 | + this.shape, | ||
12 | + this.removeTop = true, | ||
13 | + this.clipBehavior, | ||
14 | + this.modalBarrierColor, | ||
15 | + this.isDismissible = true, | ||
16 | + this.enableDrag = true, | ||
17 | + @required this.isScrollControlled, | ||
18 | + RouteSettings settings, | ||
19 | + this.enterBottomSheetDuration = const Duration(milliseconds: 250), | ||
20 | + this.exitBottomSheetDuration = const Duration(milliseconds: 200), | ||
21 | + }) : assert(isScrollControlled != null), | ||
22 | + name = "BOTTOMSHEET: ${builder.hashCode}", | ||
23 | + assert(isDismissible != null), | ||
24 | + assert(enableDrag != null), | ||
25 | + super(settings: settings); | ||
26 | + final bool isPersistent; | ||
27 | + final WidgetBuilder builder; | ||
28 | + final ThemeData theme; | ||
29 | + final bool isScrollControlled; | ||
30 | + final Color backgroundColor; | ||
31 | + final double elevation; | ||
32 | + final ShapeBorder shape; | ||
33 | + final Clip clipBehavior; | ||
34 | + final Color modalBarrierColor; | ||
35 | + final bool isDismissible; | ||
36 | + final bool enableDrag; | ||
37 | + final String name; | ||
38 | + final Duration enterBottomSheetDuration; | ||
39 | + final Duration exitBottomSheetDuration; | ||
40 | + // remove safearea from top | ||
41 | + final bool removeTop; | ||
42 | + | ||
43 | + @override | ||
44 | + Duration get transitionDuration => Duration(milliseconds: 700); | ||
45 | + | ||
46 | + @override | ||
47 | + bool get barrierDismissible => isDismissible; | ||
48 | + | ||
49 | + @override | ||
50 | + final String barrierLabel; | ||
51 | + | ||
52 | + @override | ||
53 | + Color get barrierColor => modalBarrierColor ?? Colors.black54; | ||
54 | + | ||
55 | + AnimationController _animationController; | ||
56 | + | ||
57 | + @override | ||
58 | + AnimationController createAnimationController() { | ||
59 | + assert(_animationController == null); | ||
60 | + _animationController = | ||
61 | + BottomSheet.createAnimationController(navigator.overlay); | ||
62 | + _animationController.duration = enterBottomSheetDuration; | ||
63 | + _animationController.reverseDuration = exitBottomSheetDuration; | ||
64 | + return _animationController; | ||
65 | + } | ||
66 | + | ||
67 | + @override | ||
68 | + Widget buildPage(BuildContext context, Animation<double> animation, | ||
69 | + Animation<double> secondaryAnimation) { | ||
70 | + final sheetTheme = | ||
71 | + theme?.bottomSheetTheme ?? Theme.of(context).bottomSheetTheme; | ||
72 | + // By definition, the bottom sheet is aligned to the bottom of the page | ||
73 | + // and isn't exposed to the top padding of the MediaQuery. | ||
74 | + Widget bottomSheet = MediaQuery.removePadding( | ||
75 | + context: context, | ||
76 | + removeTop: removeTop, | ||
77 | + child: Padding( | ||
78 | + padding: | ||
79 | + EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom), | ||
80 | + child: _GetModalBottomSheet<T>( | ||
81 | + route: this, | ||
82 | + backgroundColor: backgroundColor ?? | ||
83 | + sheetTheme?.modalBackgroundColor ?? | ||
84 | + sheetTheme?.backgroundColor, | ||
85 | + elevation: | ||
86 | + elevation ?? sheetTheme?.modalElevation ?? sheetTheme?.elevation, | ||
87 | + shape: shape, | ||
88 | + clipBehavior: clipBehavior, | ||
89 | + isScrollControlled: isScrollControlled, | ||
90 | + enableDrag: enableDrag, | ||
91 | + ), | ||
92 | + ), | ||
93 | + ); | ||
94 | + if (theme != null) bottomSheet = Theme(data: theme, child: bottomSheet); | ||
95 | + return bottomSheet; | ||
96 | + } | ||
97 | +} | ||
98 | + | ||
99 | +class _GetModalBottomSheet<T> extends StatefulWidget { | ||
100 | + const _GetModalBottomSheet({ | ||
101 | + Key key, | ||
102 | + this.route, | ||
103 | + this.backgroundColor, | ||
104 | + this.elevation, | ||
105 | + this.shape, | ||
106 | + this.clipBehavior, | ||
107 | + this.isScrollControlled = false, | ||
108 | + this.enableDrag = true, | ||
109 | + this.isPersistent = false, | ||
110 | + }) : assert(isScrollControlled != null), | ||
111 | + assert(enableDrag != null), | ||
112 | + super(key: key); | ||
113 | + final bool isPersistent; | ||
114 | + final GetModalBottomSheetRoute<T> route; | ||
115 | + final bool isScrollControlled; | ||
116 | + final Color backgroundColor; | ||
117 | + final double elevation; | ||
118 | + final ShapeBorder shape; | ||
119 | + final Clip clipBehavior; | ||
120 | + final bool enableDrag; | ||
121 | + | ||
122 | + @override | ||
123 | + _GetModalBottomSheetState<T> createState() => _GetModalBottomSheetState<T>(); | ||
124 | +} | ||
125 | + | ||
126 | +class _GetModalBottomSheetState<T> extends State<_GetModalBottomSheet<T>> { | ||
127 | + String _getRouteLabel(MaterialLocalizations localizations) { | ||
128 | + if ((Theme.of(context).platform == TargetPlatform.android) || | ||
129 | + (Theme.of(context).platform == TargetPlatform.fuchsia)) { | ||
130 | + return localizations.dialogLabel; | ||
131 | + } else { | ||
132 | + return ''; | ||
133 | + } | ||
134 | + } | ||
135 | + | ||
136 | + @override | ||
137 | + Widget build(BuildContext context) { | ||
138 | + assert(debugCheckHasMediaQuery(context)); | ||
139 | + assert(debugCheckHasMaterialLocalizations(context)); | ||
140 | + final mediaQuery = MediaQuery.of(context); | ||
141 | + final localizations = MaterialLocalizations.of(context); | ||
142 | + final routeLabel = _getRouteLabel(localizations); | ||
143 | + | ||
144 | + return AnimatedBuilder( | ||
145 | + animation: widget.route.animation, | ||
146 | + builder: (context, child) { | ||
147 | + // Disable the initial animation when accessible navigation is on so | ||
148 | + // that the semantics are added to the tree at the correct time. | ||
149 | + final animationValue = mediaQuery.accessibleNavigation | ||
150 | + ? 1.0 | ||
151 | + : widget.route.animation.value; | ||
152 | + return Semantics( | ||
153 | + scopesRoute: true, | ||
154 | + namesRoute: true, | ||
155 | + label: routeLabel, | ||
156 | + explicitChildNodes: true, | ||
157 | + child: ClipRect( | ||
158 | + child: CustomSingleChildLayout( | ||
159 | + delegate: _GetModalBottomSheetLayout( | ||
160 | + animationValue, widget.isScrollControlled), | ||
161 | + child: widget.isPersistent == false | ||
162 | + ? BottomSheet( | ||
163 | + animationController: widget.route._animationController, | ||
164 | + onClosing: () { | ||
165 | + if (widget.route.isCurrent) { | ||
166 | + Navigator.pop(context); | ||
167 | + } | ||
168 | + }, | ||
169 | + builder: widget.route.builder, | ||
170 | + backgroundColor: widget.backgroundColor, | ||
171 | + elevation: widget.elevation, | ||
172 | + shape: widget.shape, | ||
173 | + clipBehavior: widget.clipBehavior, | ||
174 | + enableDrag: widget.enableDrag, | ||
175 | + ) | ||
176 | + : Scaffold( | ||
177 | + bottomSheet: BottomSheet( | ||
178 | + animationController: | ||
179 | + widget.route._animationController, | ||
180 | + onClosing: () { | ||
181 | + // if (widget.route.isCurrent) { | ||
182 | + // Navigator.pop(context); | ||
183 | + // } | ||
184 | + }, | ||
185 | + builder: widget.route.builder, | ||
186 | + backgroundColor: widget.backgroundColor, | ||
187 | + elevation: widget.elevation, | ||
188 | + shape: widget.shape, | ||
189 | + clipBehavior: widget.clipBehavior, | ||
190 | + enableDrag: widget.enableDrag, | ||
191 | + ), | ||
192 | + )), | ||
193 | + ), | ||
194 | + ); | ||
195 | + }, | ||
196 | + ); | ||
197 | + } | ||
198 | +} | ||
199 | + | ||
200 | +class _GetPerModalBottomSheet<T> extends StatefulWidget { | ||
201 | + const _GetPerModalBottomSheet({ | ||
202 | + Key key, | ||
203 | + this.route, | ||
204 | + this.isPersistent, | ||
205 | + this.backgroundColor, | ||
206 | + this.elevation, | ||
207 | + this.shape, | ||
208 | + this.clipBehavior, | ||
209 | + this.isScrollControlled = false, | ||
210 | + this.enableDrag = true, | ||
211 | + }) : assert(isScrollControlled != null), | ||
212 | + assert(enableDrag != null), | ||
213 | + super(key: key); | ||
214 | + final bool isPersistent; | ||
215 | + final GetModalBottomSheetRoute<T> route; | ||
216 | + final bool isScrollControlled; | ||
217 | + final Color backgroundColor; | ||
218 | + final double elevation; | ||
219 | + final ShapeBorder shape; | ||
220 | + final Clip clipBehavior; | ||
221 | + final bool enableDrag; | ||
222 | + | ||
223 | + @override | ||
224 | + // ignore: lines_longer_than_80_chars | ||
225 | + _GetPerModalBottomSheetState<T> createState() => | ||
226 | + _GetPerModalBottomSheetState<T>(); | ||
227 | +} | ||
228 | + | ||
229 | +// ignore: lines_longer_than_80_chars | ||
230 | +class _GetPerModalBottomSheetState<T> | ||
231 | + extends State<_GetPerModalBottomSheet<T>> { | ||
232 | + String _getRouteLabel(MaterialLocalizations localizations) { | ||
233 | + if ((Theme.of(context).platform == TargetPlatform.android) || | ||
234 | + (Theme.of(context).platform == TargetPlatform.fuchsia)) { | ||
235 | + return localizations.dialogLabel; | ||
236 | + } else { | ||
237 | + return ''; | ||
238 | + } | ||
239 | + } | ||
240 | + | ||
241 | + @override | ||
242 | + Widget build(BuildContext context) { | ||
243 | + assert(debugCheckHasMediaQuery(context)); | ||
244 | + assert(debugCheckHasMaterialLocalizations(context)); | ||
245 | + final mediaQuery = MediaQuery.of(context); | ||
246 | + final localizations = MaterialLocalizations.of(context); | ||
247 | + final routeLabel = _getRouteLabel(localizations); | ||
248 | + | ||
249 | + return AnimatedBuilder( | ||
250 | + animation: widget.route.animation, | ||
251 | + builder: (context, child) { | ||
252 | + // Disable the initial animation when accessible navigation is on so | ||
253 | + // that the semantics are added to the tree at the correct time. | ||
254 | + final animationValue = mediaQuery.accessibleNavigation | ||
255 | + ? 1.0 | ||
256 | + : widget.route.animation.value; | ||
257 | + return Semantics( | ||
258 | + scopesRoute: true, | ||
259 | + namesRoute: true, | ||
260 | + label: routeLabel, | ||
261 | + explicitChildNodes: true, | ||
262 | + child: ClipRect( | ||
263 | + child: CustomSingleChildLayout( | ||
264 | + delegate: _GetModalBottomSheetLayout( | ||
265 | + animationValue, widget.isScrollControlled), | ||
266 | + child: widget.isPersistent == false | ||
267 | + ? BottomSheet( | ||
268 | + animationController: widget.route._animationController, | ||
269 | + onClosing: () { | ||
270 | + if (widget.route.isCurrent) { | ||
271 | + Navigator.pop(context); | ||
272 | + } | ||
273 | + }, | ||
274 | + builder: widget.route.builder, | ||
275 | + backgroundColor: widget.backgroundColor, | ||
276 | + elevation: widget.elevation, | ||
277 | + shape: widget.shape, | ||
278 | + clipBehavior: widget.clipBehavior, | ||
279 | + enableDrag: widget.enableDrag, | ||
280 | + ) | ||
281 | + : Scaffold( | ||
282 | + bottomSheet: BottomSheet( | ||
283 | + animationController: | ||
284 | + widget.route._animationController, | ||
285 | + onClosing: () { | ||
286 | + // if (widget.route.isCurrent) { | ||
287 | + // Navigator.pop(context); | ||
288 | + // } | ||
289 | + }, | ||
290 | + builder: widget.route.builder, | ||
291 | + backgroundColor: widget.backgroundColor, | ||
292 | + elevation: widget.elevation, | ||
293 | + shape: widget.shape, | ||
294 | + clipBehavior: widget.clipBehavior, | ||
295 | + enableDrag: widget.enableDrag, | ||
296 | + ), | ||
297 | + )), | ||
298 | + ), | ||
299 | + ); | ||
300 | + }, | ||
301 | + ); | ||
302 | + } | ||
303 | +} | ||
304 | + | ||
305 | +class _GetModalBottomSheetLayout extends SingleChildLayoutDelegate { | ||
306 | + _GetModalBottomSheetLayout(this.progress, this.isScrollControlled); | ||
307 | + | ||
308 | + final double progress; | ||
309 | + final bool isScrollControlled; | ||
310 | + | ||
311 | + @override | ||
312 | + BoxConstraints getConstraintsForChild(BoxConstraints constraints) { | ||
313 | + return BoxConstraints( | ||
314 | + minWidth: constraints.maxWidth, | ||
315 | + maxWidth: constraints.maxWidth, | ||
316 | + minHeight: 0.0, | ||
317 | + maxHeight: isScrollControlled | ||
318 | + ? constraints.maxHeight | ||
319 | + : constraints.maxHeight * 9.0 / 16.0, | ||
320 | + ); | ||
321 | + } | ||
322 | + | ||
323 | + @override | ||
324 | + Offset getPositionForChild(Size size, Size childSize) { | ||
325 | + return Offset(0.0, size.height - childSize.height * progress); | ||
326 | + } | ||
327 | + | ||
328 | + @override | ||
329 | + bool shouldRelayout(_GetModalBottomSheetLayout oldDelegate) { | ||
330 | + return progress != oldDelegate.progress; | ||
331 | + } | ||
332 | +} |
1 | +import 'package:flutter/widgets.dart'; | ||
2 | +import '../../../get_core/get_core.dart'; | ||
3 | +import '../../../get_instance/src/get_instance.dart'; | ||
4 | + | ||
5 | +class GetDialogRoute<T> extends PopupRoute<T> { | ||
6 | + GetDialogRoute({ | ||
7 | + @required RoutePageBuilder pageBuilder, | ||
8 | + bool barrierDismissible = true, | ||
9 | + String barrierLabel, | ||
10 | + Color barrierColor = const Color(0x80000000), | ||
11 | + Duration transitionDuration = const Duration(milliseconds: 200), | ||
12 | + RouteTransitionsBuilder transitionBuilder, | ||
13 | + RouteSettings settings, | ||
14 | + }) : assert(barrierDismissible != null), | ||
15 | + widget = pageBuilder, | ||
16 | + name = "DIALOG: ${pageBuilder.hashCode}", | ||
17 | + _barrierDismissible = barrierDismissible, | ||
18 | + _barrierLabel = barrierLabel, | ||
19 | + _barrierColor = barrierColor, | ||
20 | + _transitionDuration = transitionDuration, | ||
21 | + _transitionBuilder = transitionBuilder, | ||
22 | + super(settings: settings); | ||
23 | + | ||
24 | + final RoutePageBuilder widget; | ||
25 | + | ||
26 | + @override | ||
27 | + bool get barrierDismissible => _barrierDismissible; | ||
28 | + final bool _barrierDismissible; | ||
29 | + | ||
30 | + final String name; | ||
31 | + | ||
32 | + @override | ||
33 | + void dispose() { | ||
34 | + if (Get.smartManagement != SmartManagement.onlyBuilder) { | ||
35 | + WidgetsBinding.instance.addPostFrameCallback( | ||
36 | + (_) => GetInstance().removeDependencyByRoute(name)); | ||
37 | + } | ||
38 | + super.dispose(); | ||
39 | + } | ||
40 | + | ||
41 | + @override | ||
42 | + String get barrierLabel => _barrierLabel; | ||
43 | + final String _barrierLabel; | ||
44 | + | ||
45 | + @override | ||
46 | + Color get barrierColor => _barrierColor; | ||
47 | + final Color _barrierColor; | ||
48 | + | ||
49 | + @override | ||
50 | + Duration get transitionDuration => _transitionDuration; | ||
51 | + final Duration _transitionDuration; | ||
52 | + | ||
53 | + final RouteTransitionsBuilder _transitionBuilder; | ||
54 | + | ||
55 | + @override | ||
56 | + Widget buildPage(BuildContext context, Animation<double> animation, | ||
57 | + Animation<double> secondaryAnimation) { | ||
58 | + return Semantics( | ||
59 | + child: widget(context, animation, secondaryAnimation), | ||
60 | + scopesRoute: true, | ||
61 | + explicitChildNodes: true, | ||
62 | + ); | ||
63 | + } | ||
64 | + | ||
65 | + @override | ||
66 | + Widget buildTransitions(BuildContext context, Animation<double> animation, | ||
67 | + Animation<double> secondaryAnimation, Widget child) { | ||
68 | + if (_transitionBuilder == null) { | ||
69 | + return FadeTransition( | ||
70 | + opacity: CurvedAnimation( | ||
71 | + parent: animation, | ||
72 | + curve: Curves.linear, | ||
73 | + ), | ||
74 | + child: child); | ||
75 | + } // Some default transition | ||
76 | + return _transitionBuilder(context, animation, secondaryAnimation, child); | ||
77 | + } | ||
78 | +} |
-
Please register or login to post a comment