From d1aaa2feee6568b944288a3eebfe214fd303a98d Mon Sep 17 00:00:00 2001 From: gsi-alejandro Date: Wed, 15 Nov 2023 18:13:53 -0500 Subject: [PATCH] docs: Documentation website proposal --- .github/workflows/docs.yml | 35 + .gitignore | 7 +- docs/README.md | 41 + docs/babel.config.js | 3 + docs/crowdin.yml | 10 + docs/docs/about.md | 44 + docs/docs/community/_category_.json | 8 + docs/docs/community/channels.md | 7 + docs/docs/community/contribute.md | 11 + docs/docs/community/resources.md | 21 + docs/docs/concepts/_category_.json | 8 + docs/docs/concepts/dependency-management.md | 39 + docs/docs/concepts/route-management.md | 53 + docs/docs/concepts/state-management.md | 47 + docs/docs/intro.md | 91 + docs/docs/pillars/_category_.json | 8 + docs/docs/pillars/dependency-management.md | 395 + docs/docs/pillars/route-management.md | 560 ++ docs/docs/pillars/state-management.md | 769 ++ docs/docs/utils.md | 893 ++ docs/docusaurus.config.ts | 109 + docs/i18n/en/code.json | 289 + .../options.json | 14 + .../current.json | 30 + .../en/docusaurus-theme-classic/navbar.json | 30 + docs/i18n/es/code.json | 289 + .../options.json | 14 + .../current.json | 30 + .../current/about.md | 44 + .../current/community/_category_.json | 8 + .../current/community/channels.md | 7 + .../current/community/contribute.md | 11 + .../current/community/resources.md | 21 + .../current/concepts/_category_.json | 8 + .../current/concepts/dependency-management.md | 39 + .../current/concepts/route-management.md | 53 + .../current/concepts/state-management.md | 47 + .../current/intro.md | 94 + .../current/pillars/_category_.json | 8 + .../current/pillars/dependency-management.md | 404 + .../current/pillars/route-management.md | 560 ++ .../current/pillars/state-management.md | 768 ++ .../current/utils.md | 894 ++ .../es/docusaurus-theme-classic/navbar.json | 30 + docs/i18n/fr/code.json | 289 + .../options.json | 14 + .../current.json | 30 + .../current/about.md | 44 + .../current/community/_category_.json | 8 + .../current/community/channels.md | 7 + .../current/community/contribute.md | 11 + .../current/community/resources.md | 21 + .../current/concepts/_category_.json | 8 + .../current/concepts/dependency-management.md | 39 + .../current/concepts/route-management.md | 53 + .../current/concepts/state-management.md | 47 + .../current/intro.md | 94 + .../current/pillars/_category_.json | 8 + .../current/pillars/dependency-management.md | 404 + .../current/pillars/route-management.md | 560 ++ .../current/pillars/state-management.md | 768 ++ .../current/utils.md | 894 ++ .../fr/docusaurus-theme-classic/navbar.json | 30 + docs/package.json | 51 + docs/sidebars.ts | 31 + docs/src/components/Banner/index.tsx | 43 + docs/src/components/Banner/styles.module.css | 61 + docs/src/components/CodeExample/index.tsx | 10 + docs/src/components/Footer/index.tsx | 89 + docs/src/components/Footer/styles.module.css | 43 + .../src/components/HomepageFeatures/index.tsx | 78 + .../HomepageFeatures/styles.module.css | 11 + docs/src/css/custom.css | 129 + docs/src/pages/index.module.css | 61 + docs/src/pages/index.tsx | 32 + docs/static/.nojekyll | 0 docs/static/img/bg.svg | 15 + docs/static/img/discord.svg | 8 + docs/static/img/favicon.ico | Bin 0 -> 2174 bytes docs/static/img/flutter.svg | 30 + docs/static/img/footerBg.svg | 19 + docs/static/img/github.svg | 29 + docs/static/img/icon.svg | 12 + docs/static/img/img.png | Bin 0 -> 150888 bytes docs/static/img/logo.svg | 27 + docs/static/img/organization.svg | 18 + docs/static/img/productivity.svg | 15 + docs/static/img/rocket.svg | 19 + docs/static/img/slack.png | Bin 0 -> 28055 bytes docs/static/img/telegram.svg | 15 + docs/static/img/text.svg | 26 + docs/tsconfig.json | 7 + docs/yarn.lock | 8663 +++++++++++++++++ 93 files changed, 19721 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/docs.yml create mode 100644 docs/README.md create mode 100644 docs/babel.config.js create mode 100644 docs/crowdin.yml create mode 100644 docs/docs/about.md create mode 100644 docs/docs/community/_category_.json create mode 100644 docs/docs/community/channels.md create mode 100644 docs/docs/community/contribute.md create mode 100644 docs/docs/community/resources.md create mode 100644 docs/docs/concepts/_category_.json create mode 100644 docs/docs/concepts/dependency-management.md create mode 100644 docs/docs/concepts/route-management.md create mode 100644 docs/docs/concepts/state-management.md create mode 100644 docs/docs/intro.md create mode 100644 docs/docs/pillars/_category_.json create mode 100644 docs/docs/pillars/dependency-management.md create mode 100644 docs/docs/pillars/route-management.md create mode 100644 docs/docs/pillars/state-management.md create mode 100644 docs/docs/utils.md create mode 100644 docs/docusaurus.config.ts create mode 100644 docs/i18n/en/code.json create mode 100644 docs/i18n/en/docusaurus-plugin-content-blog/options.json create mode 100644 docs/i18n/en/docusaurus-plugin-content-docs/current.json create mode 100644 docs/i18n/en/docusaurus-theme-classic/navbar.json create mode 100644 docs/i18n/es/code.json create mode 100644 docs/i18n/es/docusaurus-plugin-content-blog/options.json create mode 100644 docs/i18n/es/docusaurus-plugin-content-docs/current.json create mode 100644 docs/i18n/es/docusaurus-plugin-content-docs/current/about.md create mode 100644 docs/i18n/es/docusaurus-plugin-content-docs/current/community/_category_.json create mode 100644 docs/i18n/es/docusaurus-plugin-content-docs/current/community/channels.md create mode 100644 docs/i18n/es/docusaurus-plugin-content-docs/current/community/contribute.md create mode 100644 docs/i18n/es/docusaurus-plugin-content-docs/current/community/resources.md create mode 100644 docs/i18n/es/docusaurus-plugin-content-docs/current/concepts/_category_.json create mode 100644 docs/i18n/es/docusaurus-plugin-content-docs/current/concepts/dependency-management.md create mode 100644 docs/i18n/es/docusaurus-plugin-content-docs/current/concepts/route-management.md create mode 100644 docs/i18n/es/docusaurus-plugin-content-docs/current/concepts/state-management.md create mode 100644 docs/i18n/es/docusaurus-plugin-content-docs/current/intro.md create mode 100644 docs/i18n/es/docusaurus-plugin-content-docs/current/pillars/_category_.json create mode 100644 docs/i18n/es/docusaurus-plugin-content-docs/current/pillars/dependency-management.md create mode 100644 docs/i18n/es/docusaurus-plugin-content-docs/current/pillars/route-management.md create mode 100644 docs/i18n/es/docusaurus-plugin-content-docs/current/pillars/state-management.md create mode 100644 docs/i18n/es/docusaurus-plugin-content-docs/current/utils.md create mode 100644 docs/i18n/es/docusaurus-theme-classic/navbar.json create mode 100644 docs/i18n/fr/code.json create mode 100644 docs/i18n/fr/docusaurus-plugin-content-blog/options.json create mode 100644 docs/i18n/fr/docusaurus-plugin-content-docs/current.json create mode 100644 docs/i18n/fr/docusaurus-plugin-content-docs/current/about.md create mode 100644 docs/i18n/fr/docusaurus-plugin-content-docs/current/community/_category_.json create mode 100644 docs/i18n/fr/docusaurus-plugin-content-docs/current/community/channels.md create mode 100644 docs/i18n/fr/docusaurus-plugin-content-docs/current/community/contribute.md create mode 100644 docs/i18n/fr/docusaurus-plugin-content-docs/current/community/resources.md create mode 100644 docs/i18n/fr/docusaurus-plugin-content-docs/current/concepts/_category_.json create mode 100644 docs/i18n/fr/docusaurus-plugin-content-docs/current/concepts/dependency-management.md create mode 100644 docs/i18n/fr/docusaurus-plugin-content-docs/current/concepts/route-management.md create mode 100644 docs/i18n/fr/docusaurus-plugin-content-docs/current/concepts/state-management.md create mode 100644 docs/i18n/fr/docusaurus-plugin-content-docs/current/intro.md create mode 100644 docs/i18n/fr/docusaurus-plugin-content-docs/current/pillars/_category_.json create mode 100644 docs/i18n/fr/docusaurus-plugin-content-docs/current/pillars/dependency-management.md create mode 100644 docs/i18n/fr/docusaurus-plugin-content-docs/current/pillars/route-management.md create mode 100644 docs/i18n/fr/docusaurus-plugin-content-docs/current/pillars/state-management.md create mode 100644 docs/i18n/fr/docusaurus-plugin-content-docs/current/utils.md create mode 100644 docs/i18n/fr/docusaurus-theme-classic/navbar.json create mode 100644 docs/package.json create mode 100644 docs/sidebars.ts create mode 100644 docs/src/components/Banner/index.tsx create mode 100644 docs/src/components/Banner/styles.module.css create mode 100644 docs/src/components/CodeExample/index.tsx create mode 100644 docs/src/components/Footer/index.tsx create mode 100644 docs/src/components/Footer/styles.module.css create mode 100644 docs/src/components/HomepageFeatures/index.tsx create mode 100644 docs/src/components/HomepageFeatures/styles.module.css create mode 100644 docs/src/css/custom.css create mode 100644 docs/src/pages/index.module.css create mode 100644 docs/src/pages/index.tsx create mode 100644 docs/static/.nojekyll create mode 100644 docs/static/img/bg.svg create mode 100644 docs/static/img/discord.svg create mode 100644 docs/static/img/favicon.ico create mode 100644 docs/static/img/flutter.svg create mode 100644 docs/static/img/footerBg.svg create mode 100644 docs/static/img/github.svg create mode 100644 docs/static/img/icon.svg create mode 100644 docs/static/img/img.png create mode 100644 docs/static/img/logo.svg create mode 100644 docs/static/img/organization.svg create mode 100644 docs/static/img/productivity.svg create mode 100644 docs/static/img/rocket.svg create mode 100644 docs/static/img/slack.png create mode 100644 docs/static/img/telegram.svg create mode 100644 docs/static/img/text.svg create mode 100644 docs/tsconfig.json create mode 100644 docs/yarn.lock diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 000000000..815dad0fb --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,35 @@ +name: Deploy to GitHub Pages + +on: + push: + branches: + - master + paths: + - docs/** + +permissions: + contents: write + +jobs: + deploy: + name: Deploy to GitHub Pages + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: 18 + + - name: Install dependencies + run: cd docs && yarn install --frozen-lockfile + + - name: Build documentation website + run: cd docs && yarn build + + # Popular action to deploy to GitHub Pages: + # Docs: https://github.com/peaceiris/actions-gh-pages#%EF%B8%8F-docusaurus + - name: Deploy to GitHub Pages + uses: peaceiris/actions-gh-pages@v3 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./docs/build diff --git a/.gitignore b/.gitignore index f0bff24b2..f26c2bccf 100644 --- a/.gitignore +++ b/.gitignore @@ -82,4 +82,9 @@ example/macos/Flutter/ephemeral/ example/macos/Flutter/GeneratedPluginRegistrant.swift # Coverage files -coverage/ \ No newline at end of file +coverage/ + +/docs/node_modules +/docs/.idea +/docs/build +/docs/.docusaurus \ No newline at end of file diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 000000000..aaba2fa1e --- /dev/null +++ b/docs/README.md @@ -0,0 +1,41 @@ +# Website + +This website is built using [Docusaurus 2](https://docusaurus.io/), a modern static website generator. + +### Installation + +``` +$ yarn +``` + +### Local Development + +``` +$ yarn start +``` + +This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server. + +### Build + +``` +$ yarn build +``` + +This command generates static content into the `build` directory and can be served using any static contents hosting service. + +### Deployment + +Using SSH: + +``` +$ USE_SSH=true yarn deploy +``` + +Not using SSH: + +``` +$ GIT_USER= yarn deploy +``` + +If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch. diff --git a/docs/babel.config.js b/docs/babel.config.js new file mode 100644 index 000000000..e00595dae --- /dev/null +++ b/docs/babel.config.js @@ -0,0 +1,3 @@ +module.exports = { + presets: [require.resolve('@docusaurus/core/lib/babel/preset')], +}; diff --git a/docs/crowdin.yml b/docs/crowdin.yml new file mode 100644 index 000000000..d51879e05 --- /dev/null +++ b/docs/crowdin.yml @@ -0,0 +1,10 @@ +project_id_env: 'env_value' +api_token_env: "env_value" +preserve_hierarchy: true +files: + # JSON translation files + - source: /i18n/en/**/* + translation: /i18n/%two_letters_code%/**/%original_file_name% + # Docs Markdown files + - source: /docs/**/* + translation: /i18n/%two_letters_code%/docusaurus-plugin-content-docs/current/**/%original_file_name% \ No newline at end of file diff --git a/docs/docs/about.md b/docs/docs/about.md new file mode 100644 index 000000000..fc0b4a7e5 --- /dev/null +++ b/docs/docs/about.md @@ -0,0 +1,44 @@ +--- +sidebar_position: 2 +--- + +# About GetX + +- GetX is an extra-light and powerful solution for Flutter. It combines high-performance state management, intelligent dependency injection, and route management quickly and practically. + +- GetX has 3 basic principles. This means that these are the priority for all resources in the library: **PRODUCTIVITY, PERFORMANCE AND ORGANIZATION.** + + - **PERFORMANCE:** GetX is focused on performance and minimum consumption of resources. GetX does not use Streams or ChangeNotifier. + + - **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 provide the maximum performance your application can deliver. + + Generally, the developer should be concerned with removing controllers from memory. With GetX this is not necessary because resources are removed from memory when they are not used by default. If you want to keep it in memory, you must explicitly declare "permanent: true" in your dependency. That way, in addition to saving time, you are less at risk of having unnecessary dependencies on memory. Dependency loading is also lazy by default. + + - **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/blocs 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 `MultiProvider`s. For this, GetX uses its own dependency injection feature, decoupling the DI from its view completely. + + With GetX you know where to find each feature of your application, having clean code by default. In addition to making maintenance easy, this makes the sharing of modules something that until then in Flutter was unthinkable, something totally possible. + 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. + GetX is the easiest, practical, and scalable way to build high-performance applications with the Flutter SDK. It has a large ecosystem around it that works perfectly together, it's easy for beginners, and it's accurate for experts. It is secure, stable, up-to-date, and offers a huge range of APIs built-in that are not present in the default Flutter SDK. + +- GetX is not 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. + +- GetX has a huge ecosystem, a large community, a large number of collaborators, and will be maintained as long as the Flutter exists. GetX too is capable of running with the same code on Android, iOS, Web, Mac, Linux, Windows, and on your server. + **It is possible to fully reuse your code made on the frontend on your backend with [Get Server](https://github.com/jonataslaw/get_server)**. + +**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)**. + +**In addition, to further increase your productivity, we have the +[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)** + +## Why Getx? + +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. + +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. + +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. + +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. +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. + +This library will always be updated and implementing new features. Feel free to offer PRs and contribute to them. diff --git a/docs/docs/community/_category_.json b/docs/docs/community/_category_.json new file mode 100644 index 000000000..44f54f018 --- /dev/null +++ b/docs/docs/community/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "Community", + "position": 10, + "link": { + "type": "generated-index", + "description": "Community." + } +} diff --git a/docs/docs/community/channels.md b/docs/docs/community/channels.md new file mode 100644 index 000000000..0281ccee9 --- /dev/null +++ b/docs/docs/community/channels.md @@ -0,0 +1,7 @@ +# Channels + +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. + +| **Slack** | **Discord** | **Telegram** | +| :-------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------- | +| [![Get on Slack](https://img.shields.io/badge/slack-join-orange.svg)](https://communityinviter.com/apps/getxworkspace/getx) | [![Discord Shield](https://img.shields.io/discord/722900883784073290.svg?logo=discord)](https://discord.com/invite/9Hpt99N) | [![Telegram](https://img.shields.io/badge/chat-on%20Telegram-blue.svg)](https://t.me/joinchat/PhdbJRmsZNpAqSLJL6bH7g) | \ No newline at end of file diff --git a/docs/docs/community/contribute.md b/docs/docs/community/contribute.md new file mode 100644 index 000000000..545ef8b5d --- /dev/null +++ b/docs/docs/community/contribute.md @@ -0,0 +1,11 @@ +# How to contribute + +_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._ + +- Helping to translate the readme into other languages. +- Adding documentation to the readme (a lot of Get's functions haven't been documented yet). +- Write articles or make videos teaching how to use Get (they will be inserted in the Readme and in the future in our Wiki). +- Offering PRs for code/tests. +- Including new functions. + +Any contribution is welcome! \ No newline at end of file diff --git a/docs/docs/community/resources.md b/docs/docs/community/resources.md new file mode 100644 index 000000000..7dd9df113 --- /dev/null +++ b/docs/docs/community/resources.md @@ -0,0 +1,21 @@ +# Resources + +### Articles and videos + +- [Flutter Getx EcoSystem package for arabic people](https://www.youtube.com/playlist?list=PLV1fXIAyjeuZ6M8m56zajMUwu4uE3-SL0) - Tutorial by [Pesa Coder](https://github.com/UsamaElgendy). +- [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). +- [Complete GetX™ Navigation](https://www.youtube.com/watch?v=RaqPIoJSTtI) - Route management video by Amateur Coder. +- [Complete GetX State Management](https://www.youtube.com/watch?v=CNpXbeI_slw) - State management video by Amateur Coder. +- [GetX™ Other Features](https://youtu.be/ttQtlX_Q0eU) - Utils, storage, bindings and other features video by Amateur Coder. +- [Firestore User with GetX | Todo App](https://www.youtube.com/watch?v=BiV0DcXgk58) - Video by Amateur Coder. +- [Firebase Auth with GetX | Todo App](https://www.youtube.com/watch?v=-H-T_BSgfOE) - Video by Amateur Coder. +- [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). +- [The Flutter GetX™ Ecosystem ~ Dependency Injection](https://medium.com/flutter-community/the-flutter-getx-ecosystem-dependency-injection-8e763d0ec6b9) - Dependency Injection by [Aachman Garg](https://github.com/imaachman). +- [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. +- [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. +- [GetX Flutter Firebase Auth Example](https://medium.com/@jeffmcmorris/getx-flutter-firebase-auth-example-b383c1dd1de2) - Article by Jeff McMorris. +- [Flutter State Management with GetX – Complete App](https://www.appwithflutter.com/flutter-state-management-with-getx/) - by App With Flutter. +- [Flutter Routing with Animation using Get Package](https://www.appwithflutter.com/flutter-routing-using-get-package/) - by App With Flutter. +- [A minimal example on dartpad](https://dartpad.dev/2b3d0d6f9d4e312c5fdbefc414c1727e?) - by [Roi Peker](https://github.com/roipeker) +- [GetConnect: The best way to perform API operations in Flutter with Get.](https://absyz.com/getconnect-the-best-way-to-perform-api-operations-in-flutter-with-getx/) - by [MD Sarfaraj](https://github.com/socialmad) +- [How To Create an App with GetX Architect in Flutter with Get CLI](https://www.youtube.com/watch?v=7mb4qBA7kTk&t=1380s) - by [MD Sarfaraj](https://github.com/socialmad) \ No newline at end of file diff --git a/docs/docs/concepts/_category_.json b/docs/docs/concepts/_category_.json new file mode 100644 index 000000000..70c16f706 --- /dev/null +++ b/docs/docs/concepts/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "Concepts", + "position": 3, + "link": { + "type": "generated-index", + "description": "The concepts about the 3 pillars of GetX." + } +} diff --git a/docs/docs/concepts/dependency-management.md b/docs/docs/concepts/dependency-management.md new file mode 100644 index 000000000..7ed699674 --- /dev/null +++ b/docs/docs/concepts/dependency-management.md @@ -0,0 +1,39 @@ +--- +sidebar_position: 3 +--- + +# Dependency management + +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: + +```dart +Controller controller = Get.put(Controller()); // Rather Controller controller = Controller(); +``` + +- Note: If you are using Get's State Manager, pay more attention to the bindings API, which will make it easier to connect your view to your controller. + +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. +So you can use your controller (or class Bloc) normally + +**Tip:** Get dependency management is decoupled 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 + +```dart +controller.fetchApi(); +``` + +Imagine that you have navigated through numerous routes, and you need 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: + +```dart +Controller controller = Get.find(); +//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. +``` + +And then you will be able to recover your controller data that was obtained back there: + +```dart +Text(controller.textFromApi); +``` + +### More details about dependency management + +**See a more in-depth explanation of dependency management [here](/docs/pillars/dependency-management)** \ No newline at end of file diff --git a/docs/docs/concepts/route-management.md b/docs/docs/concepts/route-management.md new file mode 100644 index 000000000..e829e24c1 --- /dev/null +++ b/docs/docs/concepts/route-management.md @@ -0,0 +1,53 @@ +--- +sidebar_position: 2 +--- + +# Route management + +If you are going to use routes/snackbars/dialogs/bottomsheets without context, GetX is excellent for you too, just see it: + +Add "Get" before your MaterialApp, turning it into GetMaterialApp + +```dart +GetMaterialApp( // Before: MaterialApp( + home: MyHome(), +) +``` + +Navigate to a new screen: + +```dart + +Get.to(NextScreen()); +``` + +Navigate to new screen with name. See more details on named routes [here](/docs/pillars/route-management#navigation-with-named-routes) + +```dart + +Get.toNamed('/details'); +``` + +To close snackbars, dialogs, bottomsheets, or anything you would normally close with Navigator.pop(context); + +```dart +Get.back(); +``` + +To go to the next screen and no option to go back to the previous screen (for use in SplashScreens, login screens, etc.) + +```dart +Get.off(NextScreen()); +``` + +To go to the next screen and cancel all previous routes (useful in shopping carts, polls, and tests) + +```dart +Get.offAll(NextScreen()); +``` + +Noticed that you didn't have 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. + +### More details about route management + +**Get works with named routes and also offers lower-level control over your routes! There is in-depth documentation [here](/docs/pillars/route-management)** \ No newline at end of file diff --git a/docs/docs/concepts/state-management.md b/docs/docs/concepts/state-management.md new file mode 100644 index 000000000..49ffc8f74 --- /dev/null +++ b/docs/docs/concepts/state-management.md @@ -0,0 +1,47 @@ +--- +sidebar_position: 1 +--- + +# State management + +Get has two different state managers: the simple state manager (we'll call it GetBuilder) and the reactive state manager (GetX/Obx) + +### Reactive State Manager + +Reactive programming can alienate many people because it is said to be complicated. GetX turns reactive programming into something quite simple: + +- You won't need to create StreamControllers. +- You won't need to create a StreamBuilder for each variable +- You will not need to create a class for each state. +- You will not need to create a get for an initial value. +- You will not need to use code generators + +Reactive programming with Get is as easy as using setState. + +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. + +This is your count variable: + +```dart +var name = 'Jonatas Borges'; +``` + +To make it observable, you just need to add ".obs" to the end of it: + +```dart +var name = 'Jonatas Borges'.obs; +``` + +And in the UI, when you want to show that value and update the screen whenever the values changes, simply do this: + +```dart +Obx(() => Text("${controller.name}")); +``` + +That's all. It's _that_ simple. + +### More details about state management + +**See an more in-depth explanation of state management [here](/docs/pillars/state-management). There you will see more examples and also the difference between the simple state manager and the reactive state manager** + +You will get a good idea of GetX power. \ No newline at end of file diff --git a/docs/docs/intro.md b/docs/docs/intro.md new file mode 100644 index 000000000..56a5ad472 --- /dev/null +++ b/docs/docs/intro.md @@ -0,0 +1,91 @@ +--- +sidebar_position: 1 +--- + +# Get Started + +### Installing + +Add Get to your pubspec.yaml file: + +```yml +dependencies: + get: +``` + +Import get in files that it will be used: + +```dart +import 'package:get/get.dart'; +``` + +### Counter App with GetX + +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. + +- Step 1: + Add "Get" before your MaterialApp, turning it into GetMaterialApp + +```dart +void main() => runApp(GetMaterialApp(home: Home())); +``` + +- 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. +- Note²: This step is 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 + +- Step 2: + Create your business logic class and place all variables, methods and controllers inside it. + You can make any variable observable using a simple ".obs". + +```dart +class Controller extends GetxController{ + var count = 0.obs; + increment() => count++; +} +``` + +- Step 3: + Create your View, use StatelessWidget and save some RAM, with Get you may no longer need to use StatefulWidget. + +```dart +class Home extends StatelessWidget { + + @override + Widget build(context) { + + // Instantiate your class using Get.put() to make it available for all "child" routes there. + final Controller c = Get.put(Controller()); + + return Scaffold( + // Use Obx(()=> to update Text() whenever count is changed. + appBar: AppBar(title: Obx(() => Text("Clicks: ${c.count}"))), + + // Replace the 8 lines Navigator.push by a simple Get.to(). You don't need context + body: Center(child: ElevatedButton( + child: Text("Go to Other"), onPressed: () => Get.to(Other()))), + floatingActionButton: + FloatingActionButton(child: Icon(Icons.add), onPressed: c.increment)); + } +} + +class Other extends StatelessWidget { + // You can ask Get to find a Controller that is being used by another page and redirect you to it. + final Controller c = Get.find(); + + @override + Widget build(context){ + // Access the updated count variable + return Scaffold(body: Center(child: Text("${c.count}"))); + } +} +``` + +Result: + +![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/counter-app-gif.gif) + +This is a simple project but it already makes clear how powerful Get is. As your project grows, this difference will become more significant. + +Get was designed to work with teams, but it makes the job of an individual developer simple. + +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! diff --git a/docs/docs/pillars/_category_.json b/docs/docs/pillars/_category_.json new file mode 100644 index 000000000..8edcfb981 --- /dev/null +++ b/docs/docs/pillars/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "The 3 Pillars", + "position": 3, + "link": { + "type": "generated-index", + "description": "The 3 pillars of GetX." + } +} diff --git a/docs/docs/pillars/dependency-management.md b/docs/docs/pillars/dependency-management.md new file mode 100644 index 000000000..eab75f5d7 --- /dev/null +++ b/docs/docs/pillars/dependency-management.md @@ -0,0 +1,395 @@ +--- +sidebar_position: 3 +--- + +# Dependency + +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: + +```dart +Controller controller = Get.put(Controller()); // Rather Controller controller = Controller(); +``` + +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. +So you can use your controller (or Bloc class) normally + +- Note: If you are using Get's State Manager, pay more attention to the [Bindings](#bindings) api, which will make easier to connect your view to your controller. +- Note²: 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 change that, you can use this dependency injection manager with no problems at all + +## Instancing methods +The methods and it's configurable parameters are: + +### Get.put() + +The most common way of inserting a dependency. Good for the controllers of your views for example. + +```dart +Get.put(SomeClass()); +Get.put(LoginController(), permanent: true); +Get.put(ListItemController, tag: "some unique string"); +``` + +This is all options you can set when using put: +```dart +Get.put( + // mandatory: the class that you want to get to save, like a controller or anything + // note: "S" means that it can be a class of any type + S dependency + + // optional: this is for when you want multiple classess that are of the same type + // since you normally get a class by using Get.find(), + // you need to use tag to tell which instance you need + // must be unique string + String tag, + + // optional: by default, get will dispose instances after they are not used anymore (example, + // the controller of a view that is closed), but you might need that the instance + // to be kept there throughout the entire app, like an instance of sharedPreferences or something + // so you use this + // defaults to false + bool permanent = false, + + // optional: allows you after using an abstract class in a test, replace it with another one and follow the test. + // defaults to false + bool overrideAbstract = false, + + // optional: allows you to create the dependency using function instead of the dependency itself. + // this one is not commonly used + InstanceBuilderCallback builder, +) +``` + +### Get.lazyPut +It is possible to lazyLoad a dependency so that it will be instantiated only when is used. Very useful for computational expensive classes or if you want to instantiate several classes in just one place (like in a Bindings class) and you know you will not gonna use that class at that time. + +```dart +/// ApiMock will only be called when someone uses Get.find for the first time +Get.lazyPut(() => ApiMock()); + +Get.lazyPut( + () { + // ... some logic if needed + return FirebaseAuth(); + }, + tag: Math.random().toString(), + fenix: true +) + +Get.lazyPut( () => Controller() ) +``` + +This is all options you can set when using lazyPut: +```dart +Get.lazyPut( + // mandatory: a method that will be executed when your class is called for the first time + InstanceBuilderCallback builder, + + // optional: same as Get.put(), it is used for when you want multiple different instance of a same class + // must be unique + String tag, + + // optional: It is similar to "permanent", the difference is that the instance is discarded when + // is not being used, but when it's use is needed again, Get will recreate the instance + // just the same as "SmartManagement.keepFactory" in the bindings api + // defaults to false + bool fenix = false + +) +``` + +### Get.putAsync +If you want to register an asynchronous instance, you can use `Get.putAsync`: + +```dart +Get.putAsync(() async { + final prefs = await SharedPreferences.getInstance(); + await prefs.setInt('counter', 12345); + return prefs; +}); + +Get.putAsync( () async => await YourAsyncClass() ) +``` + +This is all options you can set when using putAsync: +```dart +Get.putAsync( + + // mandatory: an async method that will be executed to instantiate your class + AsyncInstanceBuilderCallback builder, + + // optional: same as Get.put(), it is used for when you want multiple different instance of a same class + // must be unique + String tag, + + // optional: same as in Get.put(), used when you need to maintain that instance alive in the entire app + // defaults to false + bool permanent = false +) +``` + +### Get.create + +This one is tricky. A detailed explanation of what this is and the differences between the other one can be found on [Differences between methods:](#differences-between-methods) section + +```dart +Get.Create(() => SomeClass()); +Get.Create(() => LoginController()); +``` + +This is all options you can set when using create: + +```dart +Get.create( + // required: a function that returns a class that will be "fabricated" every + // time `Get.find()` is called + // Example: Get.create(() => YourClass()) + FcBuilderFunc builder, + + // optional: just like Get.put(), but it is used when you need multiple instances + // of a of a same class + // Useful in case you have a list that each item need it's own controller + // needs to be a unique string. Just change from tag to name + String name, + + // optional: just like int`Get.put()`, it is for when you need to keep the + // instance alive thoughout the entire app. The difference is in Get.create + // permanent is true by default + bool permanent = true +``` + +## Using instantiated methods/classes + +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: + +```dart +final controller = Get.find(); +// OR +Controller controller = Get.find(); + +// 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. +``` + +And then you will be able to recover your controller data that was obtained back there: + +```dart +Text(controller.textFromApi); +``` + +Since the returned value is a normal class, you can do anything you want: +```dart +int count = Get.find().getInt('counter'); +print(count); // out: 12345 +``` + +To remove an instance of Get: + +```dart +Get.delete(); //usually you don't need to do this because GetX already delete unused controllers +``` + +## Specifying an alternate instance + +A currently inserted instance can be replaced with a similar or extended class instance by using the `replace` or `lazyReplace` method. This can then be retrieved by using the original class. + +```dart +abstract class BaseClass {} +class ParentClass extends BaseClass {} + +class ChildClass extends ParentClass { + bool isChild = true; +} + + +Get.put(ParentClass()); + +Get.replace(ChildClass()); + +final instance = Get.find(); +print(instance is ChildClass); //true + + +class OtherClass extends BaseClass {} +Get.lazyReplace(() => OtherClass()); + +final instance = Get.find(); +print(instance is ChildClass); // false +print(instance is OtherClass); //true +``` + +## Differences between methods + +First, let's of the `fenix` of Get.lazyPut and the `permanent` of the other methods. + +The fundamental difference between `permanent` and `fenix` is how you want to store your instances. + +Reinforcing: by default, GetX deletes instances when they are not in use. +It means that: If screen 1 has controller 1 and screen 2 has controller 2 and you remove the first route from stack, (like if you use `Get.off()` or `Get.offNamed()`) the controller 1 lost its use so it will be erased. + +But if you want to opt for using `permanent:true`, then the controller will not be lost in this transition - which is very useful for services that you want to keep alive throughout the entire application. + +`fenix` in the other hand is for services that you don't worry in losing between screen changes, but when you need that service, you expect that it is alive. So basically, it will dispose the unused controller/service/class, but when you need it, it will "recreate from the ashes" a new instance. + +Proceeding with the differences between methods: + +- Get.put and Get.putAsync follows the same creation order, with the difference that the second uses an asynchronous method: those two methods creates and initializes the instance. That one is inserted directly in the memory, using the internal method `insert` with the parameters `permanent: false` and `isSingleton: true` (this isSingleton parameter only purpose is to tell if it is to use the dependency on `dependency` or if it is to use the dependency on `FcBuilderFunc`). After that, `Get.find()` is called that immediately initialize the instances that are on memory. + +- Get.create: As the name implies, it will "create" your dependency! Similar to `Get.put()`, it also calls the internal method `insert` to instancing. But `permanent` became true and `isSingleton` became false (since we are "creating" our dependency, there is no way for it to be a singleton instace, that's why is false). And because it has `permanent: true`, we have by default the benefit of not losing it between screens! Also, `Get.find()` is not called immediately, it wait to be used in the screen to be called. It is created this way to make use of the parameter `permanent`, since then, worth noticing, `Get.create()` was made with the goal of create not shared instances, but don't get disposed, like for example a button in a listView, that you want a unique instance for that list - because of that, Get.create must be used together with GetWidget. + +- Get.lazyPut: As the name implies, it is a lazy proccess. The instance is create, but it is not called to be used immediately, it remains waiting to be called. Contrary to the other methods, `insert` is not called here. Instead, the instance is inserted in another part of the memory, a part responsible to tell if the instance can be recreated or not, let's call it "factory". If we want to create something to be used later, it will not be mix with things been used right now. And here is where `fenix` magic enters: if you opt to leaving `fenix: false`, and your `smartManagement` are not `keepFactory`, then when using `Get.find` the instance will change the place in the memory from the "factory" to common instance memory area. Right after that, by default it is removed from the "factory". Now, if you opt for `fenix: true`, the instance continues to exist in this dedicated part, even going to the common area, to be called again in the future. + +## Bindings + +One of the great differentials of this package, perhaps, is the possibility of full integration of the routes, state manager and dependency manager. +When a route is removed from the Stack, all controllers, variables, and instances of objects related to it are removed from memory. If you are using streams or timers, they will be closed automatically, and you don't have to worry about any of that. +In version 2.10 Get completely implemented the Bindings API. +Now you no longer need to use the init method. You don't even have to type your controllers if you don't want to. You can start your controllers and services in the appropriate place for that. +The Binding class is a class that will decouple dependency injection, while "binding" routes to the state manager and dependency manager. +This allows Get to know which screen is being displayed when a particular controller is used and to know where and how to dispose of it. +In addition, the Binding class will allow you to have SmartManager configuration control. You can configure the dependencies to be arranged when removing a route from the stack, or when the widget that used it is laid out, or neither. You will have intelligent dependency management working for you, but even so, you can configure it as you wish. + +### Bindings class + +- Create a class and implements Binding + +```dart +class HomeBinding implements Bindings {} +``` + +Your IDE will automatically ask you to override the "dependencies" method, and you just need to click on the lamp, override the method, and insert all the classes you are going to use on that route: + +```dart +class HomeBinding implements Bindings { + @override + void dependencies() { + Get.lazyPut(() => HomeController()); + Get.put(()=> Api()); + } +} + +class DetailsBinding implements Bindings { + @override + void dependencies() { + Get.lazyPut(() => DetailsController()); + } +} +``` + +Now you just need to inform your route, that you will use that binding to make the connection between route manager, dependencies and states. + +- Using named routes: + +```dart +getPages: [ + GetPage( + name: '/', + page: () => HomeView(), + binding: HomeBinding(), + ), + GetPage( + name: '/details', + page: () => DetailsView(), + binding: DetailsBinding(), + ), +]; +``` + +- Using normal routes: + +```dart +Get.to(Home(), binding: HomeBinding()); +Get.to(DetailsView(), binding: DetailsBinding()) +``` + +There, you don't have to worry about memory management of your application anymore, Get will do it for you. + +The Binding class is called when a route is called, you can create an "initialBinding in your GetMaterialApp to insert all the dependencies that will be created. + +```dart +GetMaterialApp( + initialBinding: SampleBind(), + home: Home(), +); +``` + +### BindingsBuilder + +The default way of creating a binding is by creating a class that implements Bindings. +But alternatively, you can use `BindingsBuilder` callback so that you can simply use a function to instantiate whatever you desire. + +Example: + +```dart +getPages: [ + GetPage( + name: '/', + page: () => HomeView(), + binding: BindingsBuilder(() { + Get.lazyPut(() => ControllerX()); + Get.put(()=> Api()); + }), + ), + GetPage( + name: '/details', + page: () => DetailsView(), + binding: BindingsBuilder(() { + Get.lazyPut(() => DetailsController()); + }), + ), +]; +``` + +That way you can avoid to create one Binding class for each route making this even simpler. + +Both ways of doing work perfectly fine and we want you to use what most suit your tastes. + +### SmartManagement + +GetX by default disposes unused controllers from memory, even if a failure occurs and a widget that uses it is not properly disposed. +This is what is called the `full` mode of dependency management. +But if you want to change the way GetX controls the disposal of classes, you have `SmartManagement` class that you can set different behaviors. + +#### How to change + +If you want to change this config (which you usually don't need) this is the way: + +```dart +void main () { + runApp( + GetMaterialApp( + smartManagement: SmartManagement.onlyBuilder //here + home: Home(), + ) + ) +} +``` + +#### SmartManagement.full + +It is the default one. Dispose classes that are not being used and were not set to be permanent. In the majority of the cases you will want to keep this config untouched. If you new to GetX then don't change this. + +#### SmartManagement.onlyBuilder +With this option, only controllers started in `init:` or loaded into a Binding with `Get.lazyPut()` will be disposed. + +If you use `Get.put()` or `Get.putAsync()` or any other approach, SmartManagement will not have permissions to exclude this dependency. + +With the default behavior, even widgets instantiated with "Get.put" will be removed, unlike SmartManagement.onlyBuilder. + +#### SmartManagement.keepFactory + +Just like SmartManagement.full, it will remove it's dependencies when it's not being used anymore. However, it will keep their factory, which means it will recreate the dependency if you need that instance again. + +### How bindings work under the hood +Bindings creates transitory factories, which are created the moment you click to go to another screen, and will be destroyed as soon as the screen-changing animation happens. +This happens so fast that the analyzer will not even be able to register it. +When you navigate to this screen again, a new temporary factory will be called, so this is preferable to using SmartManagement.keepFactory, but if you don't want to create Bindings, or want to keep all your dependencies on the same Binding, it will certainly help you. +Factories take up little memory, they don't hold instances, but a function with the "shape" of that class you want. +This has a very low cost in memory, but since the purpose of this lib is to get the maximum performance possible using the minimum resources, Get removes even the factories by default. +Use whichever is most convenient for you. + +## Notes + +- DO NOT USE SmartManagement.keepFactory if you are using multiple Bindings. It was designed to be used without Bindings, or with a single Binding linked in the GetMaterialApp's initialBinding. + +- Using Bindings is completely optional, if you want you can use `Get.put()` and `Get.find()` on classes that use a given controller without any problem. + However, if you work with Services or any other abstraction, I recommend using Bindings for a better organization. \ No newline at end of file diff --git a/docs/docs/pillars/route-management.md b/docs/docs/pillars/route-management.md new file mode 100644 index 000000000..6f30832f3 --- /dev/null +++ b/docs/docs/pillars/route-management.md @@ -0,0 +1,560 @@ +--- +sidebar_position: 2 +--- + +# Route + +This is the complete explanation of all there is to Getx when the matter is route management. + +## How to use + +Add this to your pubspec.yaml file: + +```yaml +dependencies: + get: +``` + +If you are going to use routes/snackbars/dialogs/bottomsheets without context, or use the high-level Get APIs, you need to simply add "Get" before your MaterialApp, turning it into GetMaterialApp and enjoy! + +```dart +GetMaterialApp( // Before: MaterialApp( + home: MyHome(), +) +``` + +## Navigation without named routes + +To navigate to a new screen: + +```dart +Get.to(NextScreen()); +``` + +To close snackbars, dialogs, bottomsheets, or anything you would normally close with Navigator.pop(context); + +```dart +Get.back(); +``` + +To go to the next screen and no option to go back to the previous screen (for use in SplashScreens, login screens and etc.) + +```dart +Get.off(NextScreen()); +``` + +To go to the next screen and cancel all previous routes (useful in shopping carts, polls, and tests) + +```dart +Get.offAll(NextScreen()); +``` + +To navigate to the next route, and receive or update data as soon as you return from it: + +```dart +var data = await Get.to(Payment()); +``` + +on other screen, send a data for previous route: + +```dart +Get.back(result: 'success'); +``` + +And use it: + +ex: + +```dart +if(data == 'success') madeAnything(); +``` + +Don't you want to learn our syntax? +Just change the Navigator (uppercase) to navigator (lowercase), and you will have all the functions of the standard navigation, without having to use context +Example: + +```dart + +// Default Flutter navigator +Navigator.of(context).push( + context, + MaterialPageRoute( + builder: (BuildContext context) { + return HomePage(); + }, + ), +); + +// Get using Flutter syntax without needing context +navigator.push( + MaterialPageRoute( + builder: (_) { + return HomePage(); + }, + ), +); + +// Get syntax (It is much better, but you have the right to disagree) +Get.to(HomePage()); + + +``` + +## Navigation with named routes + +- If you prefer to navigate by namedRoutes, Get also supports this. + +To navigate to nextScreen + +```dart +Get.toNamed("/NextScreen"); +``` + +To navigate and remove the previous screen from the tree. + +```dart +Get.offNamed("/NextScreen"); +``` + +To navigate and remove all previous screens from the tree. + +```dart +Get.offAllNamed("/NextScreen"); +``` + +To define routes, use GetMaterialApp: + +```dart +void main() { + runApp( + GetMaterialApp( + initialRoute: '/', + getPages: [ + GetPage(name: '/', page: () => MyHomePage()), + GetPage(name: '/second', page: () => Second()), + GetPage( + name: '/third', + page: () => Third(), + transition: Transition.zoom + ), + ], + ) + ); +} +``` + +To handle navigation to non-defined routes (404 error), you can define an unknownRoute page in GetMaterialApp. + +```dart +void main() { + runApp( + GetMaterialApp( + unknownRoute: GetPage(name: '/notfound', page: () => UnknownRoutePage()), + initialRoute: '/', + getPages: [ + GetPage(name: '/', page: () => MyHomePage()), + GetPage(name: '/second', page: () => Second()), + ], + ) + ); +} +``` + +### Send data to named Routes + +Just send what you want for arguments. Get accepts anything here, whether it is a String, a Map, a List, or even a class instance. + +```dart +Get.toNamed("/NextScreen", arguments: 'Get is the best'); +``` + +on your class or controller: + +```dart +print(Get.arguments); +//print out: Get is the best +``` + +### Dynamic urls links + +Get offer advanced dynamic urls just like on the Web. Web developers have probably already wanted this feature on Flutter, and most likely have seen a package promise this feature and deliver a totally different syntax than a URL would have on web, but Get also solves that. + +```dart +Get.offAllNamed("/NextScreen?device=phone&id=354&name=Enzo"); +``` + +on your controller/bloc/stateful/stateless class: + +```dart +print(Get.parameters['id']); +// out: 354 +print(Get.parameters['name']); +// out: Enzo +``` + +You can also receive NamedParameters with Get easily: + +```dart +void main() { + runApp( + GetMaterialApp( + initialRoute: '/', + getPages: [ + GetPage( + name: '/', + page: () => MyHomePage(), + ), + GetPage( + name: '/profile/', + page: () => MyProfile(), + ), + //You can define a different page for routes with arguments, and another without arguments, but for that you must use the slash '/' on the route that will not receive arguments as above. + GetPage( + name: '/profile/:user', + page: () => UserProfile(), + ), + GetPage( + name: '/third', + page: () => Third(), + transition: Transition.cupertino + ), + ], + ) + ); +} +``` + +Send data on route name + +```dart +Get.toNamed("/profile/34954"); +``` + +On second screen take the data by parameter + +```dart +print(Get.parameters['user']); +// out: 34954 +``` + +or send multiple parameters like this + +```dart +Get.toNamed("/profile/34954?flag=true&country=italy"); +``` +or +```dart +var parameters = {"flag": "true","country": "italy",}; +Get.toNamed("/profile/34954", parameters: parameters); +``` + +On second screen take the data by parameters as usually + +```dart +print(Get.parameters['user']); +print(Get.parameters['flag']); +print(Get.parameters['country']); +// out: 34954 true italy +``` + + + +And now, all you need to do is use Get.toNamed() to navigate your named routes, without any context (you can call your routes directly from your BLoC or Controller class), and when your app is compiled to the web, your routes will appear in the url < 3 + +### Middleware + +If you want to listen Get events to trigger actions, you can to use routingCallback to it + +```dart +GetMaterialApp( + routingCallback: (routing) { + if(routing.current == '/second'){ + openAds(); + } + } +) +``` + +If you are not using GetMaterialApp, you can use the manual API to attach Middleware observer. + +```dart +void main() { + runApp( + MaterialApp( + onGenerateRoute: Router.generateRoute, + initialRoute: "/", + navigatorKey: Get.key, + navigatorObservers: [ + GetObserver(MiddleWare.observer), // HERE !!! + ], + ), + ); +} +``` + +Create a MiddleWare class + +```dart +class MiddleWare { + static observer(Routing routing) { + /// You can listen in addition to the routes, the snackbars, dialogs and bottomsheets on each screen. + ///If you need to enter any of these 3 events directly here, + ///you must specify that the event is != Than you are trying to do. + if (routing.current == '/second' && !routing.isSnackbar) { + Get.snackbar("Hi", "You are on second route"); + } else if (routing.current =='/third'){ + print('last route called'); + } + } +} +``` + +Now, use Get on your code: + +```dart +class First extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + leading: IconButton( + icon: Icon(Icons.add), + onPressed: () { + Get.snackbar("hi", "i am a modern snackbar"); + }, + ), + title: Text('First Route'), + ), + body: Center( + child: ElevatedButton( + child: Text('Open route'), + onPressed: () { + Get.toNamed("/second"); + }, + ), + ), + ); + } +} + +class Second extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + leading: IconButton( + icon: Icon(Icons.add), + onPressed: () { + Get.snackbar("hi", "i am a modern snackbar"); + }, + ), + title: Text('second Route'), + ), + body: Center( + child: ElevatedButton( + child: Text('Open route'), + onPressed: () { + Get.toNamed("/third"); + }, + ), + ), + ); + } +} + +class Third extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text("Third Route"), + ), + body: Center( + child: ElevatedButton( + onPressed: () { + Get.back(); + }, + child: Text('Go back!'), + ), + ), + ); + } +} +``` + +## Navigation without context + +### SnackBars + +To have a simple SnackBar with Flutter, you must get the context of Scaffold, or you must use a GlobalKey attached to your Scaffold + +```dart +final snackBar = SnackBar( + content: Text('Hi!'), + action: SnackBarAction( + label: 'I am a old and ugly snackbar :(', + onPressed: (){} + ), +); +// Find the Scaffold in the widget tree and use +// it to show a SnackBar. +Scaffold.of(context).showSnackBar(snackBar); +``` + +With Get: + +```dart +Get.snackbar('Hi', 'i am a modern snackbar'); +``` + +With Get, all you have to do is call your Get.snackbar from anywhere in your code or customize it however you want! + +```dart +Get.snackbar( + "Hey i'm a Get SnackBar!", // title + "It's unbelievable! I'm using SnackBar without context, without boilerplate, without Scaffold, it is something truly amazing!", // message + icon: Icon(Icons.alarm), + shouldIconPulse: true, + onTap:(){}, + barBlur: 20, + isDismissible: true, + duration: Duration(seconds: 3), +); + + + ////////// ALL FEATURES ////////// + // Color colorText, + // Duration duration, + // SnackPosition snackPosition, + // Widget titleText, + // Widget messageText, + // bool instantInit, + // Widget icon, + // bool shouldIconPulse, + // double maxWidth, + // EdgeInsets margin, + // EdgeInsets padding, + // double borderRadius, + // Color borderColor, + // double borderWidth, + // Color backgroundColor, + // Color leftBarIndicatorColor, + // List boxShadows, + // Gradient backgroundGradient, + // TextButton mainButton, + // OnTap onTap, + // bool isDismissible, + // bool showProgressIndicator, + // AnimationController progressIndicatorController, + // Color progressIndicatorBackgroundColor, + // Animation progressIndicatorValueColor, + // SnackStyle snackStyle, + // Curve forwardAnimationCurve, + // Curve reverseAnimationCurve, + // Duration animationDuration, + // double barBlur, + // double overlayBlur, + // Color overlayColor, + // Form userInputForm + /////////////////////////////////// +``` + +If you prefer the traditional snackbar, or want to customize it from scratch, including adding just one line (Get.snackbar makes use of a mandatory title and message), you can use +`Get.rawSnackbar();` which provides the RAW API on which Get.snackbar was built. + +### Dialogs + +To open dialog: + +```dart +Get.dialog(YourDialogWidget()); +``` + +To open default dialog: + +```dart +Get.defaultDialog( + onConfirm: () => print("Ok"), + middleText: "Dialog made in 3 lines of code" +); +``` + +You can also use Get.generalDialog instead of showGeneralDialog. + +For all other Flutter dialog widgets, including cupertinos, you can use Get.overlayContext instead of context, and open it anywhere in your code. +For widgets that don't use Overlay, you can use Get.context. +These two contexts will work in 99% of cases to replace the context of your UI, except for cases where inheritedWidget is used without a navigation context. + +### BottomSheets + +Get.bottomSheet is like showModalBottomSheet, but don't need of context. + +```dart +Get.bottomSheet( + Container( + child: Wrap( + children: [ + ListTile( + leading: Icon(Icons.music_note), + title: Text('Music'), + onTap: () {} + ), + ListTile( + leading: Icon(Icons.videocam), + title: Text('Video'), + onTap: () {}, + ), + ], + ), + ) +); +``` + +## Nested Navigation + +Get made Flutter's nested navigation even easier. +You don't need the context, and you will find your navigation stack by Id. + +- NOTE: Creating parallel navigation stacks can be dangerous. The ideal is not to use NestedNavigators, or to use sparingly. If your project requires it, go ahead, but keep in mind that keeping multiple navigation stacks in memory may not be a good idea for RAM consumption. + +See how simple it is: + +```dart +Navigator( + key: Get.nestedKey(1), // create a key by index + initialRoute: '/', + onGenerateRoute: (settings) { + if (settings.name == '/') { + return GetPageRoute( + page: () => Scaffold( + appBar: AppBar( + title: Text("Main"), + ), + body: Center( + child: TextButton( + color: Colors.blue, + onPressed: () { + Get.toNamed('/second', id:1); // navigate by your nested route by index + }, + child: Text("Go to second"), + ), + ), + ), + ); + } else if (settings.name == '/second') { + return GetPageRoute( + page: () => Center( + child: Scaffold( + appBar: AppBar( + title: Text("Main"), + ), + body: Center( + child: Text("second") + ), + ), + ), + ); + } + } +), +``` \ No newline at end of file diff --git a/docs/docs/pillars/state-management.md b/docs/docs/pillars/state-management.md new file mode 100644 index 000000000..9b271ff52 --- /dev/null +++ b/docs/docs/pillars/state-management.md @@ -0,0 +1,769 @@ +--- +sidebar_position: 1 +--- + +# State + +GetX does not use Streams or ChangeNotifier like other state managers. Why? In addition to building applications for android, iOS, web, windows, macos and linux, with GetX you can build server applications with the same syntax as Flutter/GetX. In order to improve response time and reduce RAM consumption, we created GetValue and GetStream, which are low latency solutions that deliver a lot of performance, at a low operating cost. We use this base to build all of our resources, including state management. + +* _Complexity_: Some state managers are complex and have a lot of boilerplate. With GetX you don't have to define a class for each event, the code is highly clean and clear, and you do a lot more by writing less. Many people have given up on Flutter because of this topic, and they now finally have a stupidly simple solution for managing states. +* _No code generators_: You spend half your development time writing your application logic. Some state managers rely on code generators to have minimally readable code. Changing a variable and having to run build_runner can be unproductive, and often the waiting time after a flutter clean will be long, and you will have to drink a lot of coffee. + +With GetX everything is reactive, and nothing depends on code generators, increasing your productivity in all aspects of your development. + +* _It does not depend on context_: You probably already needed to send the context of your view to a controller, making the View's coupling with your business logic high. You have probably had to use a dependency for a place that has no context, and had to pass the context through various classes and functions. This just doesn't exist with GetX. You have access to your controllers from within your controllers without any context. You don't need to send the context by parameter for literally nothing. +* _Granular control_: most state managers are based on ChangeNotifier. ChangeNotifier will notify all widgets that depend on it when notifyListeners is called. If you have 40 widgets on one screen, which have a variable of your ChangeNotifier class, when you update one, all of them will be rebuilt. + +With GetX, even nested widgets are respected. If you have Obx watching your ListView, and another watching a checkbox inside the ListView, when changing the CheckBox value, only it will be updated, when changing the List value, only the ListView will be updated. + +* _It only reconstructs if its variable REALLY changes_: GetX has flow control, that means if you display a Text with 'Paola', if you change the observable variable to 'Paola' again, the widget will not be reconstructed. That's because GetX knows that 'Paola' is already being displayed in Text, and will not do unnecessary reconstructions. + +Most (if not all) current state managers will rebuild on the screen. + +## Reactive State Manager + +Reactive programming can alienate many people because it is said to be complicated. GetX turns reactive programming into something quite simple: + +* You won't need to create StreamControllers. +* You won't need to create a StreamBuilder for each variable +* You will not need to create a class for each state. +* You will not need to create a get for an initial value. + +Reactive programming with Get is as easy as using setState. + +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. + +This is your count variable: + +``` dart +var name = 'Jonatas Borges'; +``` + +To make it observable, you just need to add ".obs" to the end of it: + +``` dart +var name = 'Jonatas Borges'.obs; +``` + +That's all. It's *that* simple. + +From now on, we might refer to this reactive-".obs"(ervables) variables as _Rx_. + +What did we do under the hood? We created a `Stream` of `String` s, assigned the initial value `"Jonatas Borges"` , we notified all widgets that use `"Jonatas Borges"` that they now "belong" to this variable, and when the _Rx_ value changes, they will have to change as well. + +This is the **magic of GetX**, thanks to Dart's capabilities. + +But, as we know, a `Widget` can only be changed if it is inside a function, because static classes do not have the power to "auto-change". + +You will need to create a `StreamBuilder` , subscribe to this variable to listen for changes, and create a "cascade" of nested `StreamBuilder` if you want to change several variables in the same scope, right? + +No, you don't need a `StreamBuilder` , but you are right about static classes. + +Well, in the view, we usually have a lot of boilerplate when we want to change a specific Widget, that's the Flutter way. +With **GetX** you can also forget about this boilerplate code. + +`StreamBuilder( … )` ? `initialValue: …` ? `builder: …` ? Nope, you just need to place this variable inside an `Obx()` Widget. + +``` dart +Obx (() => Text (controller.name)); +``` + +_What do you need to memorize?_ Only `Obx(() =>` . + +You are just passing that Widget through an arrow-function into an `Obx()` (the "Observer" of the _Rx_). + +`Obx` is pretty smart, and will only change if the value of `controller.name` changes. + +If `name` is `"John"` , and you change it to `"John"` ( `name.value = "John"` ), as it's the same `value` as before, nothing will change on the screen, and `Obx` , to save resources, will simply ignore the new value and not rebuild the Widget. **Isn't that amazing?** + +> So, what if I have 5 _Rx_ (observable) variables within an `Obx` ? + +It will just update when **any** of them changes. + +> And if I have 30 variables in a class, when I update one, will it update **all** the variables that are in that class? + +Nope, just the **specific Widget** that uses that _Rx_ variable. + +So, **GetX** only updates the screen, when the _Rx_ variable changes it's value. + +``` + +final isOpen = false.obs; + +// NOTHING will happen... same value. +void onButtonTap() => isOpen.value=false; +``` + +### Advantages + +**GetX()** helps you when you need **granular** control over what's being updated. + +If you do not need `unique IDs` , because all your variables will be modified when you perform an action, then use `GetBuilder` , +because it's a Simple State Updater (in blocks, like `setState()` ), made in just a few lines of code. +It was made simple, to have the least CPU impact, and just to fulfill a single purpose (a _State_ rebuild) and spend the minimum resources possible. + +If you need a **powerful** State Manager, you can't go wrong with **GetX**. + +It doesn't work with variables, but __flows__, everything in it are `Streams` under the hood. + +You can use _rxDart_ in conjunction with it, because everything are `Streams`, +you can listen to the `event` of each "_Rx_ variable", +because everything in it are `Streams`. + +It is literally a _BLoC_ approach, easier than _MobX_, and without code generators or decorations. +You can turn **anything** into an _"Observable"_ with just a `.obs` . + +### Maximum performance: + +In addition to having a smart algorithm for minimal rebuilds, **GetX** uses comparators +to make sure the State has changed. + +If you experience any errors in your app, and send a duplicate change of State, +**GetX** will ensure it will not crash. + +With **GetX** the State only changes if the `value` change. +That's the main difference between **GetX**, and using _ `computed` from MobX_. +When joining two __observables__, and one changes; the listener of that _observable_ will change as well. + +With **GetX**, if you join two variables, `GetX()` (similar to `Observer()` ) will only rebuild if it implies a real change of State. + +### Declaring a reactive variable + +You have 3 ways to turn a variable into an "observable". + +1 - The first is using **`Rx{Type}`**. + +``` dart +// initial value is recommended, but not mandatory +final name = RxString(''); +final isLogged = RxBool(false); +final count = RxInt(0); +final balance = RxDouble(0.0); +final items = RxList([]); +final myMap = RxMap({}); +``` + +2 - The second is to use **`Rx`** and use Darts Generics, `Rx` + +``` dart +final name = Rx(''); +final isLogged = Rx(false); +final count = Rx(0); +final balance = Rx(0.0); +final number = Rx(0); +final items = Rx>([]); +final myMap = Rx>({}); + +// Custom classes - it can be any class, literally +final user = Rx(); +``` + +3 - The third, more practical, easier and preferred approach, just add **`.obs`** as a property of your `value` : + +``` dart +final name = ''.obs; +final isLogged = false.obs; +final count = 0.obs; +final balance = 0.0.obs; +final number = 0.obs; +final items = [].obs; +final myMap = {}.obs; + +// Custom classes - it can be any class, literally +final user = User().obs; +``` + +##### Having a reactive state, is easy. + +As we know, _Dart_ is now heading towards _null safety_. +To be prepared, from now on, you should always start your _Rx_ variables with an **initial value**. + +> Transforming a variable into an _observable_ + _initial value_ with **GetX** is the simplest, and most practical approach. + +You will literally add a " `.obs` " to the end of your variable, and **that’s it**, you’ve made it observable, +and its `.value` , well, will be the _initial value_). + +### Using the values in the view + +``` dart +// controller file +final count1 = 0.obs; +final count2 = 0.obs; +int get sum => count1.value + count2.value; +``` + +``` dart +// view file +GetX( + builder: (controller) { + print("count 1 rebuild"); + return Text('${controller.count1.value}'); + }, +), +GetX( + builder: (controller) { + print("count 2 rebuild"); + return Text('${controller.count2.value}'); + }, +), +GetX( + builder: (controller) { + print("count 3 rebuild"); + return Text('${controller.sum}'); + }, +), +``` + +If we increment `count1.value++` , it will print: + +* `count 1 rebuild` + +* `count 3 rebuild` + +because `count1` has a value of `1` , and `1 + 0 = 1` , changing the `sum` getter value. + +If we change `count2.value++` , it will print: + +* `count 2 rebuild` + +* `count 3 rebuild` + +because `count2.value` changed, and the result of the `sum` is now `2` . + +* NOTE: By default, the very first event will rebuild the widget, even if it is the same `value`. + +This behavior exists due to Boolean variables. + +Imagine you did this: + +``` dart +var isLogged = false.obs; +``` + +And then, you checked if a user is "logged in" to trigger an event in `ever` . + +``` dart +@override +onInit() async { + ever(isLogged, fireRoute); + isLogged.value = await Preferences.hasToken(); +} + +fireRoute(logged) { + if (logged) { + Get.off(Home()); + } else { + Get.off(Login()); + } +} +``` + +if `hasToken` was `false` , there would be no change to `isLogged` , so `ever()` would never be called. +To avoid this type of behavior, the first change to an _observable_ will always trigger an event, +even if it contains the same `.value` . + +You can remove this behavior if you want, using: +`isLogged.firstRebuild = false;` + +### Conditions to rebuild + +In addition, Get provides refined state control. You can condition an event (such as adding an object to a list), on a certain condition. + +``` dart +// First parameter: condition, must return true or false. +// Second parameter: the new value to apply if the condition is true. +list.addIf(item < limit, item); +``` + +Without decorations, without a code generator, without complications :smile: + +Do you know Flutter's counter app? Your Controller class might look like this: + +``` dart +class CountController extends GetxController { + final count = 0.obs; +} +``` + +With a simple: + +``` dart +controller.count.value++ +``` + +You could update the counter variable in your UI, regardless of where it is stored. + +### Where .obs can be used + +You can transform anything on obs. Here are two ways of doing it: + +* You can convert your class values to obs + +``` dart +class RxUser { + final name = "Camila".obs; + final age = 18.obs; +} +``` + +* or you can convert the entire class to be an observable + +``` dart +class User { + User({String name, int age}); + var name; + var age; +} + +// when instantianting: +final user = User(name: "Camila", age: 18).obs; +``` + +### Note about Lists + +Lists are completely observable as are the objects within it. That way, if you add a value to a list, it will automatically rebuild the widgets that use it. + +You also don't need to use ".value" with lists, the amazing dart api allowed us to remove that. +Unfortunaly primitive types like String and int cannot be extended, making the use of .value mandatory, but that won't be a problem if you work with gets and setters for these. + +``` dart +// On the controller +final String title = 'User Info:'.obs +final list = List().obs; + +// on the view +Text(controller.title.value), // String need to have .value in front of it +ListView.builder ( + itemCount: controller.list.length // lists don't need it +) +``` + +When you are making your own classes observable, there is a different way to update them: + +``` dart +// on the model file +// we are going to make the entire class observable instead of each attribute +class User() { + User({this.name = '', this.age = 0}); + String name; + int age; +} + +// on the controller file +final user = User().obs; +// when you need to update the user variable: +user.update( (user) { // this parameter is the class itself that you want to update +user.name = 'Jonny'; +user.age = 18; +}); +// an alternative way of update the user variable: +user(User(name: 'João', age: 35)); + +// on view: +Obx(()=> Text("Name ${user.value.name}: Age: ${user.value.age}")) +// you can also access the model values without the .value: +user().name; // notice that is the user variable, not the class (variable has lowercase u) +``` + +You don't have to work with sets if you don't want to. you can use the "assign 'and" assignAll "api. +The "assign" api will clear your list, and add a single object that you want to start there. +The "assignAll" api will clear the existing list and add any iterable objects that you inject into it. + +### Why i have to use .value + +We could remove the obligation to use 'value' to `String` and `int` with a simple decoration and code generator, but the purpose of this library is precisely avoid external dependencies. We want to offer an environment ready for programming, involving the essentials (management of routes, dependencies and states), in a simple, lightweight and performant way, without a need of an external package. + +You can literally add 3 letters to your pubspec (get) and a colon and start programming. All solutions included by default, from route management to state management, aim at ease, productivity and performance. + +The total weight of this library is less than that of a single state manager, even though it is a complete solution, and that is what you must understand. + +If you are bothered by `.value` , and like a code generator, MobX is a great alternative, and you can use it in conjunction with Get. For those who want to add a single dependency in pubspec and start programming without worrying about the version of a package being incompatible with another, or if the error of a state update is coming from the state manager or dependency, or still, do not want to worrying about the availability of controllers, whether literally "just programming", get is just perfect. + +If you have no problem with the MobX code generator, or have no problem with the BLoC boilerplate, you can simply use Get for routes, and forget that it has state manager. Get SEM and RSM were born out of necessity, my company had a project with more than 90 controllers, and the code generator simply took more than 30 minutes to complete its tasks after a Flutter Clean on a reasonably good machine, if your project it has 5, 10, 15 controllers, any state manager will supply you well. If you have an absurdly large project, and code generator is a problem for you, you have been awarded this solution. + +Obviously, if someone wants to contribute to the project and create a code generator, or something similar, I will link in this readme as an alternative, my need is not the need for all devs, but for now I say, there are good solutions that already do that, like MobX. + +### Obx() + +Typing in Get using Bindings is unnecessary. you can use the Obx widget instead of GetX which only receives the anonymous function that creates a widget. +Obviously, if you don't use a type, you will need to have an instance of your controller to use the variables, or use `Get.find()` .value or Controller.to.value to retrieve the value. + +### Workers + +Workers will assist you, triggering specific callbacks when an event occurs. + +``` dart +/// Called every time `count1` changes. +ever(count1, (_) => print("$_ has been changed")); + +/// Called only first time the variable $_ is changed +once(count1, (_) => print("$_ was changed once")); + +/// Anti DDos - Called every time the user stops typing for 1 second, for example. +debounce(count1, (_) => print("debouce$_"), time: Duration(seconds: 1)); + +/// Ignore all changes within 1 second. +interval(count1, (_) => print("interval $_"), time: Duration(seconds: 1)); +``` + +All workers (except `debounce` ) have a `condition` named parameter, which can be a `bool` or a callback that returns a `bool` . +This `condition` defines when the `callback` function executes. + +All workers returns a `Worker` instance, that you can use to cancel ( via `dispose()` ) the worker. + + +* **`ever`** + +is called every time the _Rx_ variable emits a new value. + +* **`everAll`** + +Much like `ever` , but it takes a `List` of _Rx_ values Called every time its variable is changed. That's it. + +* **`once`** + +'once' is called only the first time the variable has been changed. + +* **`debounce`** + +'debounce' is very useful in search functions, where you only want the API to be called when the user finishes typing. If the user types "Jonny", you will have 5 searches in the APIs, by the letter J, o, n, n, and y. With Get this does not happen, because you will have a "debounce" Worker that will only be triggered at the end of typing. + +* **`interval`** + +'interval' is different from the debouce. debouce if the user makes 1000 changes to a variable within 1 second, he will send only the last one after the stipulated timer (the default is 800 milliseconds). Interval will instead ignore all user actions for the stipulated period. If you send events for 1 minute, 1000 per second, debounce will only send you the last one, when the user stops strafing events. interval will deliver events every second, and if set to 3 seconds, it will deliver 20 events that minute. This is recommended to avoid abuse, in functions where the user can quickly click on something and get some advantage (imagine that the user can earn coins by clicking on something, if he clicked 300 times in the same minute, he would have 300 coins, using interval, you can set a time frame for 3 seconds, and even then clicking 300 or a thousand times, the maximum he would get in 1 minute would be 20 coins, clicking 300 or 1 million times). The debounce is suitable for anti-DDos, for functions like search where each change to onChange would cause a query to your api. Debounce will wait for the user to stop typing the name, to make the request. If it were used in the coin scenario mentioned above, the user would only win 1 coin, because it is only executed, when the user "pauses" for the established time. + +* NOTE: Workers should always be used when starting a Controller or Class, so it should always be on onInit (recommended), Class constructor, or the initState of a StatefulWidget (this practice is not recommended in most cases, but it shouldn't have any side effects). + +## Simple State Manager + +Get has a state manager that is extremely light and easy, which does not use ChangeNotifier, will meet the need especially for those new to Flutter, and will not cause problems for large applications. + +GetBuilder is aimed precisely at multiple state control. Imagine that you added 30 products to a cart, you click delete one, at the same time that the list is updated, the price is updated and the badge in the shopping cart is updated to a smaller number. This type of approach makes GetBuilder killer, because it groups states and changes them all at once without any "computational logic" for that. GetBuilder was created with this type of situation in mind, since for ephemeral change of state, you can use setState and you would not need a state manager for this. + +That way, if you want an individual controller, you can assign IDs for that, or use GetX. This is up to you, remembering that the more "individual" widgets you have, the more the performance of GetX will stand out, while the performance of GetBuilder should be superior, when there is multiple change of state. + +### Advantages + +1. Update only the required widgets. + +2. Does not use changeNotifier, it is the state manager that uses less memory (close to 0mb). + +3. Forget StatefulWidget! With Get you will never need it. With the other state managers, you will probably have to use a StatefulWidget to get the instance of your Provider, BLoC, MobX Controller, etc. But have you ever stopped to think that your appBar, your scaffold, and most of the widgets that are in your class are stateless? So why save the state of an entire class, if you can only save the state of the Widget that is stateful? Get solves that, too. Create a Stateless class, make everything stateless. If you need to update a single component, wrap it with GetBuilder, and its state will be maintained. + +4. Organize your project for real! Controllers must not be in your UI, place your TextEditController, or any controller you use within your Controller class. + +5. Do you need to trigger an event to update a widget as soon as it is rendered? GetBuilder has the property "initState", just like StatefulWidget, and you can call events from your controller, directly from it, no more events being placed in your initState. + +6. Do you need to trigger an action like closing streams, timers and etc? GetBuilder also has the dispose property, where you can call events as soon as that widget is destroyed. + +7. Use streams only if necessary. You can use your StreamControllers inside your controller normally, and use StreamBuilder also normally, but remember, a stream reasonably consumes memory, reactive programming is beautiful, but you shouldn't abuse it. 30 streams open simultaneously can be worse than changeNotifier (and changeNotifier is very bad). + +8. Update widgets without spending ram for that. Get stores only the GetBuilder creator ID, and updates that GetBuilder when necessary. The memory consumption of the get ID storage in memory is very low even for thousands of GetBuilders. When you create a new GetBuilder, you are actually sharing the state of GetBuilder that has a creator ID. A new state is not created for each GetBuilder, which saves A LOT OF ram for large applications. Basically your application will be entirely Stateless, and the few Widgets that will be Stateful (within GetBuilder) will have a single state, and therefore updating one will update them all. The state is just one. + +9. Get is omniscient and in most cases it knows exactly the time to take a controller out of memory. You should not worry about when to dispose of a controller, Get knows the best time to do this. + +### Usage + +``` dart +// Create controller class and extends GetxController +class Controller extends GetxController { + int counter = 0; + void increment() { + counter++; + update(); // use update() to update counter variable on UI when increment be called + } +} +// On your Stateless/Stateful class, use GetBuilder to update Text when increment be called +GetBuilder( + init: Controller(), // INIT IT ONLY THE FIRST TIME + builder: (_) => Text( + '${_.counter}', + ), +) +//Initialize your controller only the first time. The second time you are using ReBuilder for the same controller, do not use it again. Your controller will be automatically removed from memory as soon as the widget that marked it as 'init' is deployed. You don't have to worry about that, Get will do it automatically, just make sure you don't start the same controller twice. +``` + +**Done!** + +* You have already learned how to manage states with Get. + +* Note: You may want a larger organization, and not use the init property. For that, you can create a class and extends Binding class, and within it mention the controllers that will be created within that route. Controllers will not be created at that time, on the contrary, this is just a statement, so that the first time you use a Controller, Get will know where to look. Get will remain lazyLoad, and will continue to dispose Controllers when they are no longer needed. See the pub.dev example to see how it works. + +If you navigate many routes and need data that was in your previously used controller, you just need to use GetBuilder Again (with no init): + +``` dart +class OtherClass extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + body: Center( + child: GetBuilder( + builder: (s) => Text('${s.counter}'), + ), + ), + ); + } + +``` + +If you need to use your controller in many other places, and outside of GetBuilder, just create a get in your controller and have it easily. (or use `Get.find()` ) + +``` dart +class Controller extends GetxController { + + /// You do not need that. I recommend using it just for ease of syntax. + /// with static method: Controller.to.increment(); + /// with no static method: Get.find().increment(); + /// There is no difference in performance, nor any side effect of using either syntax. Only one does not need the type, and the other the IDE will autocomplete it. + static Controller get to => Get.find(); // add this line + + int counter = 0; + void increment() { + counter++; + update(); + } +} +``` + +And then you can access your controller directly, that way: + +``` dart +FloatingActionButton( + onPressed: () { + Controller.to.increment(), + } // This is incredibly simple! + child: Text("${Controller.to.counter}"), +), +``` + +When you press FloatingActionButton, all widgets that are listening to the 'counter' variable will be updated automatically. + +### How it handles controllers + +Let's say we have this: + +`Class a => Class B (has controller X) => Class C (has controller X)` + +In class A the controller is not yet in memory, because you have not used it yet (Get is lazyLoad). In class B you used the controller, and it entered memory. In class C you used the same controller as in class B, Get will share the state of controller B with controller C, and the same controller is still in memory. If you close screen C and screen B, Get will automatically take controller X out of memory and free up resources, because Class a is not using the controller. If you navigate to B again, controller X will enter memory again, if instead of going to class C, you return to class A again, Get will take the controller out of memory in the same way. If class C didn't use the controller, and you took class B out of memory, no class would be using controller X and likewise it would be disposed of. The only exception that can mess with Get, is if you remove B from the route unexpectedly, and try to use the controller in C. In this case, the creator ID of the controller that was in B was deleted, and Get was programmed to remove it from memory every controller that has no creator ID. If you intend to do this, add the "autoRemove: false" flag to class B's GetBuilder and use adoptID = true; in class C's GetBuilder. + +### You won't need StatefulWidgets anymore + +Using StatefulWidgets means storing the state of entire screens unnecessarily, even because if you need to minimally rebuild a widget, you will embed it in a Consumer/Observer/BlocProvider/GetBuilder/GetX/Obx, which will be another StatefulWidget. +The StatefulWidget class is a class larger than StatelessWidget, which will allocate more RAM, and this may not make a significant difference between one or two classes, but it will most certainly do when you have 100 of them! +Unless you need to use a mixin, like TickerProviderStateMixin, it will be totally unnecessary to use a StatefulWidget with Get. + +You can call all methods of a StatefulWidget directly from a GetBuilder. +If you need to call initState() or dispose() method for example, you can call them directly; + +``` dart +GetBuilder( + initState: (_) => Controller.to.fetchApi(), + dispose: (_) => Controller.to.closeStreams(), + builder: (s) => Text('${s.username}'), +), +``` + +A much better approach than this is to use the onInit() and onClose() method directly from your controller. + +``` dart +@override +void onInit() { + fetchApi(); + super.onInit(); +} +``` + +* NOTE: If you want to start a method at the moment the controller is called for the first time, you DON'T NEED to use constructors for this, in fact, using a performance-oriented package like Get, this borders on bad practice, because it deviates from the logic in which the controllers are created or allocated (if you create an instance of this controller, the constructor will be called immediately, you will be populating a controller before it is even used, you are allocating memory without it being in use, this definitely hurts the principles of this library). The onInit() methods; and onClose(); were created for this, they will be called when the Controller is created, or used for the first time, depending on whether you are using Get.lazyPut or not. If you want, for example, to make a call to your API to populate data, you can forget about the old-fashioned method of initState/dispose, just start your call to the api in onInit, and if you need to execute any command like closing streams, use the onClose() for that. + +### Why it exists + +The purpose of this package is precisely to give you a complete solution for navigation of routes, management of dependencies and states, using the least possible dependencies, with a high degree of decoupling. Get engages all high and low level Flutter APIs within itself, to ensure that you work with the least possible coupling. We centralize everything in a single package, to ensure that you don't have any kind of coupling in your project. That way, you can put only widgets in your view, and leave the part of your team that works with the business logic free, to work with the business logic without depending on any element of the View. This provides a much cleaner working environment, so that part of your team works only with widgets, without worrying about sending data to your controller, and part of your team works only with the business logic in its breadth, without depending on no element of the view. + +So to simplify this: +You don't need to call methods in initState and send them by parameter to your controller, nor use your controller constructor for that, you have the onInit() method that is called at the right time for you to start your services. +You do not need to call the device, you have the onClose() method that will be called at the exact moment when your controller is no longer needed and will be removed from memory. That way, leave views for widgets only, refrain from any kind of business logic from it. + +Do not call a dispose method inside GetxController, it will not do anything, remember that the controller is not a Widget, you should not "dispose" it, and it will be automatically and intelligently removed from memory by Get. If you used any stream on it and want to close it, just insert it into the close method. Example: + +``` dart +class Controller extends GetxController { + StreamController user = StreamController(); + StreamController name = StreamController(); + + /// close stream = onClose method, not dispose. + @override + void onClose() { + user.close(); + name.close(); + super.onClose(); + } +} +``` + +Controller life cycle: + +* onInit() where it is created. +* onClose() where it is closed to make any changes in preparation for the delete method +* deleted: you do not have access to this API because it is literally removing the controller from memory. It is literally deleted, without leaving any trace. + +### Other ways of using it + +You can use Controller instance directly on GetBuilder value: + +``` dart +GetBuilder( + init: Controller(), + builder: (value) => Text( + '${value.counter}', //here + ), +), +``` + +You may also need an instance of your controller outside of your GetBuilder, and you can use these approaches to achieve this: + +``` dart +class Controller extends GetxController { + static Controller get to => Get.find(); +[...] +} +// on you view: +GetBuilder( + init: Controller(), // use it only first time on each controller + builder: (_) => Text( + '${Controller.to.counter}', //here + ) +), +``` + +or + +``` dart +class Controller extends GetxController { + // static Controller get to => Get.find(); // with no static get +[...] +} +// on stateful/stateless class +GetBuilder( + init: Controller(), // use it only first time on each controller + builder: (_) => Text( + '${Get.find().counter}', //here + ), +), +``` + +* You can use "non-canonical" approaches to do this. If you are using some other dependency manager, like get_it, modular, etc., and just want to deliver the controller instance, you can do this: + +``` dart +Controller controller = Controller(); +[...] +GetBuilder( + init: controller, //here + builder: (_) => Text( + '${controller.counter}', // here + ), +), + +``` + +### Unique IDs + +If you want to refine a widget's update control with GetBuilder, you can assign them unique IDs: + +``` dart +GetBuilder( + id: 'text' + init: Controller(), // use it only first time on each controller + builder: (_) => Text( + '${Get.find().counter}', //here + ), +), +``` + +And update it this form: + +``` dart +update(['text']); +``` + +You can also impose conditions for the update: + +``` dart +update(['text'], counter < 10); +``` + +GetX does this automatically and only reconstructs the widget that uses the exact variable that was changed, if you change a variable to the same as the previous one and that does not imply a change of state , GetX will not rebuild the widget to save memory and CPU cycles (3 is being displayed on the screen, and you change the variable to 3 again. In most state managers, this will cause a new rebuild, but with GetX the widget will only is rebuilt again, if in fact his state has changed). + +## Mixing the two state managers + +Some people opened a feature request, as they wanted to use only one type of reactive variable, and the other mechanics, and needed to insert an Obx into a GetBuilder for this. Thinking about it MixinBuilder was created. It allows both reactive changes by changing ".obs" variables, and mechanical updates via update(). However, of the 4 widgets he is the one that consumes the most resources, since in addition to having a Subscription to receive change events from his children, he subscribes to the update method of his controller. + +Extending GetxController is important, as they have life cycles, and can "start" and "end" events in their onInit() and onClose() methods. You can use any class for this, but I strongly recommend you use the GetxController class to place your variables, whether they are observable or not. + +## StateMixin + +Another way to handle your `UI` state is use the `StateMixin` . +To implement it, use the `with` to add the `StateMixin` +to your controller which allows a T model. + +``` dart +class Controller extends GetController with StateMixin{} +``` + +The `change()` method change the State whenever we want. +Just pass the data and the status in this way: + +```dart +change(data, status: RxStatus.success()); +``` + +RxStatus allow these status: + +``` dart +RxStatus.loading(); +RxStatus.success(); +RxStatus.empty(); +RxStatus.error('message'); +``` + +To represent it in the UI, use: + +```dart +class OtherClass extends GetView { + @override + Widget build(BuildContext context) { + return Scaffold( + + body: controller.obx( + (state)=>Text(state.name), + + // here you can put your custom loading indicator, but + // by default would be Center(child:CircularProgressIndicator()) + onLoading: CustomLoadingIndicator(), + onEmpty: Text('No data found'), + + // here also you can set your own error widget, but by + // default will be an Center(child:Text(error)) + onError: (error)=>Text(error), + ), + ); +} +``` + +## GetBuilder vs GetX vs Obx vs MixinBuilder + +In a decade working with programming I was able to learn some valuable lessons. + +My first contact with reactive programming was so "wow, this is incredible" and in fact reactive programming is incredible. +However, it is not suitable for all situations. Often all you need is to change the state of 2 or 3 widgets at the same time, or an ephemeral change of state, in which case reactive programming is not bad, but it is not appropriate. + +Reactive programming has a higher RAM consumption that can be compensated for by the individual workflow, which will ensure that only one widget is rebuilt and when necessary, but creating a list with 80 objects, each with several streams is not a good one idea. Open the dart inspect and check how much a StreamBuilder consumes, and you'll understand what I'm trying to tell you. + +With that in mind, I created the simple state manager. It is simple, and that is exactly what you should demand from it: updating state in blocks in a simple way, and in the most economical way. + +GetBuilder is very economical in RAM, and there is hardly a more economical approach than him (at least I can't imagine one, if it exists, please let us know). + +However, GetBuilder is still a mechanical state manager, you need to call update() just like you would need to call Provider's notifyListeners(). + +There are other situations where reactive programming is really interesting, and not working with it is the same as reinventing the wheel. With that in mind, GetX was created to provide everything that is most modern and advanced in a state manager. It updates only what is necessary and when necessary, if you have an error and send 300 state changes simultaneously, GetX will filter and update the screen only if the state actually changes. + +GetX is still more economical than any other reactive state manager, but it consumes a little more RAM than GetBuilder. Thinking about it and aiming to maximize the consumption of resources that Obx was created. Unlike GetX and GetBuilder, you will not be able to initialize a controller inside an Obx, it is just a Widget with a StreamSubscription that receives change events from your children, that's all. It is more economical than GetX, but loses to GetBuilder, which was to be expected, since it is reactive, and GetBuilder has the most simplistic approach that exists, of storing a widget's hashcode and its StateSetter. With Obx you don't need to write your controller type, and you can hear the change from multiple different controllers, but it needs to be initialized before, either using the example approach at the beginning of this readme, or using the Bindings class. \ No newline at end of file diff --git a/docs/docs/utils.md b/docs/docs/utils.md new file mode 100644 index 000000000..5c7387621 --- /dev/null +++ b/docs/docs/utils.md @@ -0,0 +1,893 @@ +--- +sidebar_position: 4 +--- + +# Utils + +## Internationalization + +### Translations + +Translations are kept as a simple key-value dictionary map. +To add custom translations, create a class and extend `Translations`. + + +```dart +import 'package:get/get.dart'; + +class Messages extends Translations { + @override + Map> get keys => { + 'en_US': { + 'hello': 'Hello World', + }, + 'de_DE': { + 'hello': 'Hallo Welt', + } + }; +} +``` + +#### Using translations + +Just append `.tr` to the specified key and it will be translated, using the current value of `Get.locale` and `Get.fallbackLocale`. + +```dart +Text('title'.tr); +``` + +#### Using translation with singular and plural + +```dart +var products = []; +Text('singularKey'.trPlural('pluralKey', products.length, Args)); +``` + +#### Using translation with parameters + +```dart +import 'package:get/get.dart'; + + +Map> get keys => { + 'en_US': { + 'logged_in': 'logged in as @name with email @email', + }, + 'es_ES': { + 'logged_in': 'iniciado sesión como @name con e-mail @email', + } +}; + +Text('logged_in'.trParams({ + 'name': 'Jhon', + 'email': 'jhon@example.com' + })); +``` + +### Locales + +Pass parameters to `GetMaterialApp` to define the locale and translations. + +```dart +return GetMaterialApp( + translations: Messages(), // your translations + locale: Locale('en', 'US'), // translations will be displayed in that locale + fallbackLocale: Locale('en', 'UK'), // specify the fallback locale in case an invalid locale is selected. +); +``` + +#### Change locale + +Call `Get.updateLocale(locale)` to update the locale. Translations then automatically use the new locale. + +```dart +var locale = Locale('en', 'US'); +Get.updateLocale(locale); +``` + +#### System locale + +To read the system locale, you could use `Get.deviceLocale`. + +```dart +return GetMaterialApp( + locale: Get.deviceLocale, +); +``` + +## Change Theme + +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™**. + +You can create your custom theme and simply add it within `Get.changeTheme` without any boilerplate for that: + +```dart +Get.changeTheme(ThemeData.light()); +``` + +If you want to create something like a button that changes the Theme in `onTap`, you can combine two **GetX™** APIs for that: + +- The api that checks if the dark `Theme` is being used. +- And the `Theme` Change API, you can just put this within an `onPressed`: + +```dart +Get.changeTheme(Get.isDarkMode? ThemeData.light(): ThemeData.dark()); +``` + +When `.darkmode` is activated, it will switch to the _light theme_, and when the _light theme_ becomes active, it will change to _dark theme_. + +## GetConnect + +GetConnect is an easy way to communicate from your back to your front with http or websockets + +### Default configuration + +You can simply extend GetConnect and use the GET/POST/PUT/DELETE/SOCKET methods to communicate with your Rest API or websockets. + +```dart +class UserProvider extends GetConnect { + // Get request + Future getUser(int id) => get('http://youapi/users/$id'); + // Post request + Future postUser(Map data) => post('http://youapi/users', body: data); + // Post request with File + Future> postCases(List image) { + final form = FormData({ + 'file': MultipartFile(image, filename: 'avatar.png'), + 'otherFile': MultipartFile(image, filename: 'cover.png'), + }); + return post('http://youapi/users/upload', form); + } + + GetSocket userMessages() { + return socket('https://yourapi/users/socket'); + } +} +``` + +### Custom configuration + +GetConnect is highly customizable You can define base Url, as answer modifiers, as Requests modifiers, define an authenticator, and even the number of attempts in which it will try to authenticate itself, in addition to giving the possibility to define a standard decoder that will transform all your requests into your Models without any additional configuration. + +```dart +class HomeProvider extends GetConnect { + @override + void onInit() { + // All request will pass to jsonEncode so CasesModel.fromJson() + httpClient.defaultDecoder = CasesModel.fromJson; + httpClient.baseUrl = 'https://api.covid19api.com'; + // baseUrl = 'https://api.covid19api.com'; // It define baseUrl to + // Http and websockets if used with no [httpClient] instance + + // It's will attach 'apikey' property on header from all requests + httpClient.addRequestModifier((request) { + request.headers['apikey'] = '12345678'; + return request; + }); + + // Even if the server sends data from the country "Brazil", + // it will never be displayed to users, because you remove + // that data from the response, even before the response is delivered + httpClient.addResponseModifier((request, response) { + CasesModel model = response.body; + if (model.countries.contains('Brazil')) { + model.countries.remove('Brazilll'); + } + }); + + httpClient.addAuthenticator((request) async { + final response = await get("http://yourapi/token"); + final token = response.body['token']; + // Set the header + request.headers['Authorization'] = "$token"; + return request; + }); + + //Autenticator will be called 3 times if HttpStatus is + //HttpStatus.unauthorized + httpClient.maxAuthRetries = 3; + } + + @override + Future> getCases(String path) => get(path); +} +``` + +## GetPage Middleware + +The GetPage has now new property that takes a list of GetMiddleWare and run them in the specific order. + +**Note**: When GetPage has a Middlewares, all the children of this page will have the same middlewares automatically. + +### Priority + +The Order of the Middlewares to run can be set by the priority in the GetMiddleware. + +```dart +final middlewares = [ + GetMiddleware(priority: 2), + GetMiddleware(priority: 5), + GetMiddleware(priority: 4), + GetMiddleware(priority: -8), +]; +``` + +those middlewares will be run in this order **-8 => 2 => 4 => 5** + +### Redirect + +This function will be called when the page of the called route is being searched for. It takes RouteSettings as a result to redirect to. Or give it null and there will be no redirecting. + +```dart +RouteSettings redirect(String route) { + final authService = Get.find(); + return authService.authed.value ? null : RouteSettings(name: '/login') +} +``` + +### onPageCalled + +This function will be called when this Page is called before anything created +you can use it to change something about the page or give it new page + +```dart +GetPage onPageCalled(GetPage page) { + final authService = Get.find(); + return page.copyWith(title: 'Welcome ${authService.UserName}'); +} +``` + +### OnBindingsStart + +This function will be called right before the Bindings are initialize. +Here you can change Bindings for this page. + +```dart +List onBindingsStart(List bindings) { + final authService = Get.find(); + if (authService.isAdmin) { + bindings.add(AdminBinding()); + } + return bindings; +} +``` + +### OnPageBuildStart + +This function will be called right after the Bindings are initialize. +Here you can do something after that you created the bindings and before creating the page widget. + +```dart +GetPageBuilder onPageBuildStart(GetPageBuilder page) { + print('bindings are ready'); + return page; +} +``` + +### OnPageBuilt + +This function will be called right after the GetPage.page function is called and will give you the result of the function. and take the widget that will be showed. + +### OnPageDispose + +This function will be called right after disposing all the related objects (Controllers, views, ...) of the page. + +## Other Advanced APIs + +```dart +// give the current args from currentScreen +Get.arguments + +// give name of previous route +Get.previousRoute + +// give the raw route to access for example, rawRoute.isFirst() +Get.rawRoute + +// give access to Routing API from GetObserver +Get.routing + +// check if snackbar is open +Get.isSnackbarOpen + +// check if dialog is open +Get.isDialogOpen + +// check if bottomsheet is open +Get.isBottomSheetOpen + +// remove one route. +Get.removeRoute() + +// back repeatedly until the predicate returns true. +Get.until() + +// go to next route and remove all the previous routes until the predicate returns true. +Get.offUntil() + +// go to next named route and remove all the previous routes until the predicate returns true. +Get.offNamedUntil() + +//Check in what platform the app is running +GetPlatform.isAndroid +GetPlatform.isIOS +GetPlatform.isMacOS +GetPlatform.isWindows +GetPlatform.isLinux +GetPlatform.isFuchsia + +//Check the device type +GetPlatform.isMobile +GetPlatform.isDesktop +//All platforms are supported independently in web! +//You can tell if you are running inside a browser +//on Windows, iOS, OSX, Android, etc. +GetPlatform.isWeb + + +// Equivalent to : MediaQuery.of(context).size.height, +// but immutable. +Get.height +Get.width + +// Gives the current context of the Navigator. +Get.context + +// Gives the context of the snackbar/dialog/bottomsheet in the foreground, anywhere in your code. +Get.contextOverlay + +// Note: the following methods are extensions on context. Since you +// have access to context in any place of your UI, you can use it anywhere in the UI code + +// If you need a changeable height/width (like Desktop or browser windows that can be scaled) you will need to use context. +context.width +context.height + +// Gives you the power to define half the screen, a third of it and so on. +// Useful for responsive applications. +// param dividedBy (double) optional - default: 1 +// param reducedBy (double) optional - default: 0 +context.heightTransformer() +context.widthTransformer() + +/// Similar to MediaQuery.sizeOf(context); +context.mediaQuerySize() + +/// Similar to MediaQuery.paddingOf(context); +context.mediaQueryPadding() + +/// Similar to MediaQuery.viewPaddingOf(context); +context.mediaQueryViewPadding() + +/// Similar to MediaQuery.viewInsetsOf(context); +context.mediaQueryViewInsets() + +/// Similar to MediaQuery.orientationOf(context); +context.orientation() + +/// Check if device is on landscape mode +context.isLandscape() + +/// Check if device is on portrait mode +context.isPortrait() + +/// Similar to MediaQuery.devicePixelRatioOf(context); +context.devicePixelRatio() + +/// Similar to MediaQuery.textScaleFactorOf(context); +context.textScaleFactor() + +/// Get the shortestSide from screen +context.mediaQueryShortestSide() + +/// True if width be larger than 800 +context.showNavbar() + +/// True if the shortestSide is smaller than 600p +context.isPhone() + +/// True if the shortestSide is largest than 600p +context.isSmallTablet() + +/// True if the shortestSide is largest than 720p +context.isLargeTablet() + +/// True if the current device is Tablet +context.isTablet() + +/// Returns a value according to the screen size +/// can give value for: +/// watch: if the shortestSide is smaller than 300 +/// mobile: if the shortestSide is smaller than 600 +/// tablet: if the shortestSide is smaller than 1200 +/// desktop: if width is largest than 1200 +context.responsiveValue() +``` + +### Optional Global Settings and Manual configurations + +GetMaterialApp configures everything for you, but if you want to configure Get manually. + +```dart +MaterialApp( + navigatorKey: Get.key, + navigatorObservers: [GetObserver()], +); +``` + +You will also be able to use your own Middleware within `GetObserver`, this will not influence anything. + +```dart +MaterialApp( + navigatorKey: Get.key, + navigatorObservers: [ + GetObserver(MiddleWare.observer) // Here + ], +); +``` + +You can create _Global Settings_ for `Get`. Just add `Get.config` to your code before pushing any route. +Or do it directly in your `GetMaterialApp` + +```dart +GetMaterialApp( + enableLog: true, + defaultTransition: Transition.fade, + opaqueRoute: Get.isOpaqueRouteDefault, + popGesture: Get.isPopGestureEnable, + transitionDuration: Get.defaultDurationTransition, + defaultGlobalState: Get.defaultGlobalState, +); + +Get.config( + enableLog = true, + defaultPopGesture = true, + defaultTransition = Transitions.cupertino +) +``` + +You can optionally redirect all the logging messages from `Get`. +If you want to use your own, favourite logging package, +and want to capture the logs there: + +```dart +GetMaterialApp( + enableLog: true, + logWriterCallback: localLogWriter, +); + +void localLogWriter(String text, {bool isError = false}) { + // pass the message to your favourite logging package here + // please note that even if enableLog: false log messages will be pushed in this callback + // you get check the flag if you want through GetConfig.isLogEnable +} + +``` + +### Local State Widgets + +These Widgets allows you to manage a single value, and keep the state ephemeral and locally. +We have flavours for Reactive and Simple. +For instance, you might use them to toggle obscureText in a `TextField`, maybe create a custom +Expandable Panel, or maybe modify the current index in `BottomNavigationBar` while changing the content +of the body in a `Scaffold`. + +#### ValueBuilder + +A simplification of `StatefulWidget` that works with a `.setState` callback that takes the updated value. + +```dart +ValueBuilder( + initialValue: false, + builder: (value, updateFn) => Switch( + value: value, + onChanged: updateFn, // same signature! you could use ( newValue ) => updateFn( newValue ) + ), + // if you need to call something outside the builder method. + onUpdate: (value) => print("Value updated: $value"), + onDispose: () => print("Widget unmounted"), +), +``` + +#### ObxValue + +Similar to [`ValueBuilder`](#valuebuilder), but this is the Reactive version, you pass a Rx instance (remember the magical .obs?) and +updates automatically... isn't it awesome? + +```dart +ObxValue((data) => Switch( + value: data.value, + onChanged: data, // Rx has a _callable_ function! You could use (flag) => data.value = flag, + ), + false.obs, +), +``` + +## Useful tips + +`.obs`ervables (also known as _Rx_ Types) have a wide variety of internal methods and operators. + +> Is very common to _believe_ that a property with `.obs` **IS** the actual value... but make no mistake! +> We avoid the Type declaration of the variable, because Dart's compiler is smart enough, and the code +> looks cleaner, but: + +```dart +var message = 'Hello world'.obs; +print( 'Message "$message" has Type ${message.runtimeType}'); +``` + +Even if `message` _prints_ the actual String value, the Type is **RxString**! + +So, you can't do `message.substring( 0, 4 )`. +You have to access the real `value` inside the _observable_: +The most "used way" is `.value`, but, did you know that you can also use... + +```dart +final name = 'GetX'.obs; +// only "updates" the stream, if the value is different from the current one. +name.value = 'Hey'; + +// All Rx properties are "callable" and returns the new value. +// but this approach does not accepts `null`, the UI will not rebuild. +name('Hello'); + +// is like a getter, prints 'Hello'. +name() ; + +/// numbers: + +final count = 0.obs; + +// You can use all non mutable operations from num primitives! +count + 1; + +// Watch out! this is only valid if `count` is not final, but var +count += 1; + +// You can also compare against values: +count > 2; + +/// booleans: + +final flag = false.obs; + +// switches the value between true/false +flag.toggle(); + + +/// all types: + +// Sets the `value` to null. +flag.nil(); + +// All toString(), toJson() operations are passed down to the `value` +print( count ); // calls `toString()` inside for RxInt + +final abc = [0,1,2].obs; +// Converts the value to a json Array, prints RxList +// Json is supported by all Rx types! +print('json: ${jsonEncode(abc)}, type: ${abc.runtimeType}'); + +// RxMap, RxList and RxSet are special Rx types, that extends their native types. +// but you can work with a List as a regular list, although is reactive! +abc.add(12); // pushes 12 to the list, and UPDATES the stream. +abc[3]; // like Lists, reads the index 3. + + +// equality works with the Rx and the value, but hashCode is always taken from the value +final number = 12.obs; +print( number == 12 ); // prints > true + +/// Custom Rx Models: + +// toJson(), toString() are deferred to the child, so you can implement override on them, and print() the observable directly. + +class User { + String name, last; + int age; + User({this.name, this.last, this.age}); + + @override + String toString() => '$name $last, $age years old'; +} + +final user = User(name: 'John', last: 'Doe', age: 33).obs; + +// `user` is "reactive", but the properties inside ARE NOT! +// So, if we change some variable inside of it... +user.value.name = 'Roi'; +// The widget will not rebuild!, +// `Rx` don't have any clue when you change something inside user. +// So, for custom classes, we need to manually "notify" the change. +user.refresh(); + +// or we can use the `update()` method! +user.update((value){ + value.name='Roi'; +}); + +print( user ); +``` +## StateMixin + +Another way to handle your `UI` state is use the `StateMixin` . +To implement it, use the `with` to add the `StateMixin` +to your controller which allows a T model. + +``` dart +class Controller extends GetController with StateMixin{} +``` + +The `change()` method change the State whenever we want. +Just pass the data and the status in this way: + +```dart +change(data, status: RxStatus.success()); +``` + +RxStatus allow these status: + +``` dart +RxStatus.loading(); +RxStatus.success(); +RxStatus.empty(); +RxStatus.error('message'); +``` + +To represent it in the UI, use: + +```dart +class OtherClass extends GetView { + @override + Widget build(BuildContext context) { + return Scaffold( + + body: controller.obx( + (state)=>Text(state.name), + + // here you can put your custom loading indicator, but + // by default would be Center(child:CircularProgressIndicator()) + onLoading: CustomLoadingIndicator(), + onEmpty: Text('No data found'), + + // here also you can set your own error widget, but by + // default will be an Center(child:Text(error)) + onError: (error)=>Text(error), + ), + ); +} +``` + +#### GetView + +I love this Widget, is so simple, yet, so useful! + +Is a `const Stateless` Widget that has a getter `controller` for a registered `Controller`, that's all. + +```dart + class AwesomeController extends GetController { + final String title = 'My Awesome View'; + } + + // ALWAYS remember to pass the `Type` you used to register your controller! + class AwesomeView extends GetView { + @override + Widget build(BuildContext context) { + return Container( + padding: EdgeInsets.all(20), + child: Text(controller.title), // just call `controller.something` + ); + } + } +``` + +#### GetResponsiveView + +Extend this widget to build responsive view. +this widget contains the `screen` property that have all +information about the screen size and type. + +##### How to use it + +You have two options to build it. + +- with `builder` method you return the widget to build. +- with methods `desktop`, `tablet`,`phone`, `watch`. the specific + method will be built when the screen type matches the method + when the screen is [ScreenType.Tablet] the `tablet` method + will be exuded and so on. + **Note:** If you use this method please set the property `alwaysUseBuilder` to `false` + +With `settings` property you can set the width limit for the screen types. + +![example](https://github.com/SchabanBo/get_page_example/blob/master/docs/Example.gif?raw=true) +Code to this screen +[code](https://github.com/SchabanBo/get_page_example/blob/master/lib/pages/responsive_example/responsive_view.dart) + +#### GetWidget + +Most people have no idea about this Widget, or totally confuse the usage of it. +The use case is very rare, but very specific: It `caches` a Controller. +Because of the _cache_, can't be a `const Stateless`. + +> So, when do you need to "cache" a Controller? + +If you use, another "not so common" feature of **GetX**: `Get.create()`. + +`Get.create(()=>Controller())` will generate a new `Controller` each time you call +`Get.find()`, + +That's where `GetWidget` shines... as you can use it, for example, +to keep a list of Todo items. So, if the widget gets "rebuilt", it will keep the same controller instance. + +#### GetxService + +This class is like a `GetxController`, it shares the same lifecycle ( `onInit()`, `onReady()`, `onClose()`). +But has no "logic" inside of it. It just notifies **GetX** Dependency Injection system, that this subclass +**can not** be removed from memory. + +So is super useful to keep your "Services" always reachable and active with `Get.find()`. Like: +`ApiService`, `StorageService`, `CacheService`. + +```dart +Future main() async { + await initServices(); /// AWAIT SERVICES INITIALIZATION. + runApp(SomeApp()); +} + +/// Is a smart move to make your Services intiialize before you run the Flutter app. +/// as you can control the execution flow (maybe you need to load some Theme configuration, +/// apiKey, language defined by the User... so load SettingService before running ApiService. +/// so GetMaterialApp() doesnt have to rebuild, and takes the values directly. +void initServices() async { + print('starting services ...'); + /// Here is where you put get_storage, hive, shared_pref initialization. + /// or moor connection, or whatever that's async. + await Get.putAsync(() => DbService().init()); + await Get.putAsync(SettingsService()).init(); + print('All services started...'); +} + +class DbService extends GetxService { + Future init() async { + print('$runtimeType delays 2 sec'); + await 2.delay(); + print('$runtimeType ready!'); + return this; + } +} + +class SettingsService extends GetxService { + void init() async { + print('$runtimeType delays 1 sec'); + await 1.delay(); + print('$runtimeType ready!'); + } +} + +``` + +The only way to actually delete a `GetxService`, is with `Get.reset()` which is like a +"Hot Reboot" of your app. So remember, if you need absolute persistence of a class instance during the +lifetime of your app, use `GetxService`. + + +### Tests + +You can test your controllers like any other class, including their lifecycles: + +```dart +class Controller extends GetxController { + @override + void onInit() { + super.onInit(); + //Change value to name2 + name.value = 'name2'; + } + + @override + void onClose() { + name.value = ''; + super.onClose(); + } + + final name = 'name1'.obs; + + void changeName() => name.value = 'name3'; +} + +void main() { + test(''' +Test the state of the reactive variable "name" across all of its lifecycles''', + () { + /// You can test the controller without the lifecycle, + /// but it's not recommended unless you're not using + /// GetX dependency injection + final controller = Controller(); + expect(controller.name.value, 'name1'); + + /// If you are using it, you can test everything, + /// including the state of the application after each lifecycle. + Get.put(controller); // onInit was called + expect(controller.name.value, 'name2'); + + /// Test your functions + controller.changeName(); + expect(controller.name.value, 'name3'); + + /// onClose was called + Get.delete(); + + expect(controller.name.value, ''); + }); +} +``` + +#### Tips + +##### Mockito or mocktail +If you need to mock your GetxController/GetxService, you should extend GetxController, and mixin it with Mock, that way + +```dart +class NotificationServiceMock extends GetxService with Mock implements NotificationService {} +``` + +##### Using Get.reset() +If you are testing widgets, or test groups, use Get.reset at the end of your test or in tearDown to reset all settings from your previous test. + +##### Get.testMode +if you are using your navigation in your controllers, use `Get.testMode = true` at the beginning of your main. + + +# Breaking changes from 2.0 + +1- Rx types: + +| Before | After | +| ------- | ---------- | +| StringX | `RxString` | +| IntX | `RxInt` | +| MapX | `RxMap` | +| ListX | `RxList` | +| NumX | `RxNum` | +| DoubleX | `RxDouble` | + +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. + +2- NamedRoutes +Before: + +```dart +GetMaterialApp( + namedRoutes: { + '/': GetRoute(page: Home()), + } +) +``` + +Now: + +```dart +GetMaterialApp( + getPages: [ + GetPage(name: '/', page: () => Home()), + ] +) +``` + +Why this change? +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. +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: + +```dart + +GetStorage box = GetStorage(); + +GetMaterialApp( + getPages: [ + GetPage(name: '/', page:(){ + return box.hasData('token') ? Home() : Login(); + }) + ] +) +``` \ No newline at end of file diff --git a/docs/docusaurus.config.ts b/docs/docusaurus.config.ts new file mode 100644 index 000000000..a9fc34679 --- /dev/null +++ b/docs/docusaurus.config.ts @@ -0,0 +1,109 @@ +import {themes as prismThemes} from 'prism-react-renderer'; +import type {Config} from '@docusaurus/types'; +import type * as Preset from '@docusaurus/preset-classic'; + +const config: Config = { + title: 'GetX', + tagline: 'Enhance dev flutter experience', + favicon: 'img/favicon.ico', + + // Set the production url of your site here + url: 'https://jonataslaw.github.io', + // Set the // pathname under which your site is served + // For GitHub pages deployment, it is often '//' + baseUrl: '/getx/', + trailingSlash: false, + + // GitHub pages deployment config. + // If you aren't using GitHub pages, you don't need these. + organizationName: 'jonataslaw', // Usually your GitHub org/user name. + projectName: 'getx', // Usually your repo name. + + onBrokenLinks: 'warn', + onBrokenMarkdownLinks: 'warn', + + // Even if you don't use internationalization, you can use this field to set + // useful metadata like html lang. For example, if your site is Chinese, you + // may want to replace "en" with "zh-Hans". + i18n: { + defaultLocale: 'en', + locales: ['en', 'es', 'fr'], + localeConfigs: { + en: { + htmlLang: 'en-GB', + } + }, + }, + presets: [ + [ + 'classic', + { + docs: { + sidebarPath: './sidebars.ts', + // Please change this to your repo. + // Remove this to remove the "edit this page" links. + editUrl: + 'https://github.com/jonataslaw/getx', + }, + blog: { + showReadingTime: true, + // Please change this to your repo. + // Remove this to remove the "edit this page" links. + editUrl: + 'https://github.com/jonataslaw/getx', + }, + theme: { + customCss: './src/css/custom.css', + }, + } satisfies Preset.Options, + ], + ], + + themeConfig: { + // Replace with your project's social card + image: 'img/docusaurus-social-card.jpg', + navbar: { + title: '', + logo: { + alt: 'Site Logo', + src: 'img/logo.svg', + }, + items: [ + { + type: 'docSidebar', + sidebarId: 'tutorialSidebar', + position: 'right', + label: 'Get Started', + }, + {to: '/docs/about', label: 'About', position: 'right'}, + {to: '/docs/category/concepts', label: 'Concepts', position: 'right'}, + {to: '/docs/category/the-3-pillars', label: 'Pillars', position: 'right'}, + {to: '/docs/utils', label: 'Utils', position: 'right'}, + {to: '/docs/category/community', label: 'Community', position: 'right'}, + { + type: 'localeDropdown', + position: 'right', + }, + { + href: "https://github.com/jonataslaw/getx", + position: "right", + className: "header-github-link", + "aria-label": "GitHub repository", + }, + ], + }, + footer: {}, + prism: { + theme: prismThemes.github, + darkTheme: prismThemes.dracula, + additionalLanguages: ['dart'], + }, + colorMode: { + defaultMode: 'dark', + disableSwitch: false, + respectPrefersColorScheme: false, + }, + } satisfies Preset.ThemeConfig, +}; + +export default config; diff --git a/docs/i18n/en/code.json b/docs/i18n/en/code.json new file mode 100644 index 000000000..6285da200 --- /dev/null +++ b/docs/i18n/en/code.json @@ -0,0 +1,289 @@ +{ + "theme.ErrorPageContent.title": { + "message": "This page crashed.", + "description": "The title of the fallback page when the page crashed" + }, + "theme.blog.archive.title": { + "message": "Archive", + "description": "The page & hero title of the blog archive page" + }, + "theme.blog.archive.description": { + "message": "Archive", + "description": "The page & hero description of the blog archive page" + }, + "theme.blog.paginator.navAriaLabel": { + "message": "Blog list page navigation", + "description": "The ARIA label for the blog pagination" + }, + "theme.blog.paginator.newerEntries": { + "message": "Newer Entries", + "description": "The label used to navigate to the newer blog posts page (previous page)" + }, + "theme.blog.paginator.olderEntries": { + "message": "Older Entries", + "description": "The label used to navigate to the older blog posts page (next page)" + }, + "theme.BackToTopButton.buttonAriaLabel": { + "message": "Scroll back to top", + "description": "The ARIA label for the back to top button" + }, + "theme.blog.post.paginator.navAriaLabel": { + "message": "Blog post page navigation", + "description": "The ARIA label for the blog posts pagination" + }, + "theme.blog.post.paginator.newerPost": { + "message": "Newer Post", + "description": "The blog post button label to navigate to the newer/previous post" + }, + "theme.blog.post.paginator.olderPost": { + "message": "Older Post", + "description": "The blog post button label to navigate to the older/next post" + }, + "theme.blog.post.plurals": { + "message": "One post|{count} posts", + "description": "Pluralized label for \"{count} posts\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.blog.tagTitle": { + "message": "{nPosts} tagged with \"{tagName}\"", + "description": "The title of the page for a blog tag" + }, + "theme.tags.tagsPageLink": { + "message": "View All Tags", + "description": "The label of the link targeting the tag list page" + }, + "theme.colorToggle.ariaLabel": { + "message": "Switch between dark and light mode (currently {mode})", + "description": "The ARIA label for the navbar color mode toggle" + }, + "theme.colorToggle.ariaLabel.mode.dark": { + "message": "dark mode", + "description": "The name for the dark color mode" + }, + "theme.colorToggle.ariaLabel.mode.light": { + "message": "light mode", + "description": "The name for the light color mode" + }, + "theme.docs.DocCard.categoryDescription": { + "message": "{count} items", + "description": "The default description for a category card in the generated index about how many items this category includes" + }, + "theme.docs.breadcrumbs.navAriaLabel": { + "message": "Breadcrumbs", + "description": "The ARIA label for the breadcrumbs" + }, + "theme.docs.paginator.navAriaLabel": { + "message": "Docs pages", + "description": "The ARIA label for the docs pagination" + }, + "theme.docs.paginator.previous": { + "message": "Previous", + "description": "The label used to navigate to the previous doc" + }, + "theme.docs.paginator.next": { + "message": "Next", + "description": "The label used to navigate to the next doc" + }, + "theme.docs.tagDocListPageTitle.nDocsTagged": { + "message": "One doc tagged|{count} docs tagged", + "description": "Pluralized label for \"{count} docs tagged\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.docs.tagDocListPageTitle": { + "message": "{nDocsTagged} with \"{tagName}\"", + "description": "The title of the page for a docs tag" + }, + "theme.docs.versionBadge.label": { + "message": "Version: {versionLabel}" + }, + "theme.docs.versions.unreleasedVersionLabel": { + "message": "This is unreleased documentation for {siteTitle} {versionLabel} version.", + "description": "The label used to tell the user that he's browsing an unreleased doc version" + }, + "theme.docs.versions.unmaintainedVersionLabel": { + "message": "This is documentation for {siteTitle} {versionLabel}, which is no longer actively maintained.", + "description": "The label used to tell the user that he's browsing an unmaintained doc version" + }, + "theme.docs.versions.latestVersionSuggestionLabel": { + "message": "For up-to-date documentation, see the {latestVersionLink} ({versionLabel}).", + "description": "The label used to tell the user to check the latest version" + }, + "theme.docs.versions.latestVersionLinkLabel": { + "message": "latest version", + "description": "The label used for the latest version suggestion link label" + }, + "theme.common.editThisPage": { + "message": "Edit this page", + "description": "The link label to edit the current page" + }, + "theme.common.headingLinkTitle": { + "message": "Direct link to {heading}", + "description": "Title for link to heading" + }, + "theme.lastUpdated.atDate": { + "message": " on {date}", + "description": "The words used to describe on which date a page has been last updated" + }, + "theme.lastUpdated.byUser": { + "message": " by {user}", + "description": "The words used to describe by who the page has been last updated" + }, + "theme.lastUpdated.lastUpdatedAtBy": { + "message": "Last updated{atDate}{byUser}", + "description": "The sentence used to display when a page has been last updated, and by who" + }, + "theme.NotFound.title": { + "message": "Page Not Found", + "description": "The title of the 404 page" + }, + "theme.navbar.mobileVersionsDropdown.label": { + "message": "Versions", + "description": "The label for the navbar versions dropdown on mobile view" + }, + "theme.tags.tagsListLabel": { + "message": "Tags:", + "description": "The label alongside a tag list" + }, + "theme.AnnouncementBar.closeButtonAriaLabel": { + "message": "Close", + "description": "The ARIA label for close button of announcement bar" + }, + "theme.admonition.caution": { + "message": "caution", + "description": "The default label used for the Caution admonition (:::caution)" + }, + "theme.admonition.danger": { + "message": "danger", + "description": "The default label used for the Danger admonition (:::danger)" + }, + "theme.admonition.info": { + "message": "info", + "description": "The default label used for the Info admonition (:::info)" + }, + "theme.admonition.note": { + "message": "note", + "description": "The default label used for the Note admonition (:::note)" + }, + "theme.admonition.tip": { + "message": "tip", + "description": "The default label used for the Tip admonition (:::tip)" + }, + "theme.admonition.warning": { + "message": "warning", + "description": "The default label used for the Warning admonition (:::warning)" + }, + "theme.blog.sidebar.navAriaLabel": { + "message": "Blog recent posts navigation", + "description": "The ARIA label for recent posts in the blog sidebar" + }, + "theme.CodeBlock.copied": { + "message": "Copied", + "description": "The copied button label on code blocks" + }, + "theme.CodeBlock.copyButtonAriaLabel": { + "message": "Copy code to clipboard", + "description": "The ARIA label for copy code blocks button" + }, + "theme.CodeBlock.copy": { + "message": "Copy", + "description": "The copy button label on code blocks" + }, + "theme.CodeBlock.wordWrapToggle": { + "message": "Toggle word wrap", + "description": "The title attribute for toggle word wrapping button of code block lines" + }, + "theme.DocSidebarItem.expandCategoryAriaLabel": { + "message": "Expand sidebar category '{label}'", + "description": "The ARIA label to expand the sidebar category" + }, + "theme.DocSidebarItem.collapseCategoryAriaLabel": { + "message": "Collapse sidebar category '{label}'", + "description": "The ARIA label to collapse the sidebar category" + }, + "theme.NavBar.navAriaLabel": { + "message": "Main", + "description": "The ARIA label for the main navigation" + }, + "theme.NotFound.p1": { + "message": "We could not find what you were looking for.", + "description": "The first paragraph of the 404 page" + }, + "theme.NotFound.p2": { + "message": "Please contact the owner of the site that linked you to the original URL and let them know their link is broken.", + "description": "The 2nd paragraph of the 404 page" + }, + "theme.navbar.mobileLanguageDropdown.label": { + "message": "Languages", + "description": "The label for the mobile language switcher dropdown" + }, + "theme.blog.post.readMore": { + "message": "Read More", + "description": "The label used in blog post item excerpts to link to full blog posts" + }, + "theme.blog.post.readMoreLabel": { + "message": "Read more about {title}", + "description": "The ARIA label for the link to full blog posts from excerpts" + }, + "theme.blog.post.readingTime.plurals": { + "message": "One min read|{readingTime} min read", + "description": "Pluralized label for \"{readingTime} min read\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.docs.breadcrumbs.home": { + "message": "Home page", + "description": "The ARIA label for the home page in the breadcrumbs" + }, + "theme.docs.sidebar.collapseButtonTitle": { + "message": "Collapse sidebar", + "description": "The title attribute for collapse button of doc sidebar" + }, + "theme.docs.sidebar.collapseButtonAriaLabel": { + "message": "Collapse sidebar", + "description": "The title attribute for collapse button of doc sidebar" + }, + "theme.docs.sidebar.navAriaLabel": { + "message": "Docs sidebar", + "description": "The ARIA label for the sidebar navigation" + }, + "theme.TOCCollapsible.toggleButtonLabel": { + "message": "On this page", + "description": "The label used by the button on the collapsible TOC component" + }, + "theme.docs.sidebar.expandButtonTitle": { + "message": "Expand sidebar", + "description": "The ARIA label and title attribute for expand button of doc sidebar" + }, + "theme.docs.sidebar.expandButtonAriaLabel": { + "message": "Expand sidebar", + "description": "The ARIA label and title attribute for expand button of doc sidebar" + }, + "theme.docs.sidebar.closeSidebarButtonAriaLabel": { + "message": "Close navigation bar", + "description": "The ARIA label for close button of mobile sidebar" + }, + "theme.docs.sidebar.toggleSidebarButtonAriaLabel": { + "message": "Toggle navigation bar", + "description": "The ARIA label for hamburger menu button of mobile navigation" + }, + "theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel": { + "message": "← Back to main menu", + "description": "The label of the back button to return to main menu, inside the mobile navbar sidebar secondary menu (notably used to display the docs sidebar)" + }, + "theme.ErrorPageContent.tryAgain": { + "message": "Try again", + "description": "The label of the button to try again rendering when the React error boundary captures an error" + }, + "theme.common.skipToMainContent": { + "message": "Skip to main content", + "description": "The skip to content label used for accessibility, allowing to rapidly navigate to main content with keyboard tab/enter navigation" + }, + "theme.tags.tagsPageTitle": { + "message": "Tags", + "description": "The title of the tag list page" + }, + "theme.unlistedContent.title": { + "message": "Unlisted page", + "description": "The unlisted content banner title" + }, + "theme.unlistedContent.message": { + "message": "This page is unlisted. Search engines will not index it, and only users having a direct link can access it.", + "description": "The unlisted content banner message" + } +} diff --git a/docs/i18n/en/docusaurus-plugin-content-blog/options.json b/docs/i18n/en/docusaurus-plugin-content-blog/options.json new file mode 100644 index 000000000..9239ff706 --- /dev/null +++ b/docs/i18n/en/docusaurus-plugin-content-blog/options.json @@ -0,0 +1,14 @@ +{ + "title": { + "message": "Blog", + "description": "The title for the blog used in SEO" + }, + "description": { + "message": "Blog", + "description": "The description for the blog used in SEO" + }, + "sidebar.title": { + "message": "Recent posts", + "description": "The label for the left sidebar" + } +} diff --git a/docs/i18n/en/docusaurus-plugin-content-docs/current.json b/docs/i18n/en/docusaurus-plugin-content-docs/current.json new file mode 100644 index 000000000..0b88caca0 --- /dev/null +++ b/docs/i18n/en/docusaurus-plugin-content-docs/current.json @@ -0,0 +1,30 @@ +{ + "version.label": { + "message": "Next", + "description": "The label for version current" + }, + "sidebar.tutorialSidebar.category.The 3 Pillars": { + "message": "The 3 Pillars", + "description": "The label for category The 3 Pillars in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.The 3 Pillars.link.generated-index.description": { + "message": "The 3 pillars of GetX.", + "description": "The generated-index page description for category The 3 Pillars in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.Community": { + "message": "Community", + "description": "The label for category Community in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.Community.link.generated-index.description": { + "message": "Community.", + "description": "The generated-index page description for category Community in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.Concepts": { + "message": "Concepts", + "description": "The label for category Concepts in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.Concepts.link.generated-index.description": { + "message": "The concepts about the 3 pillars of GetX.", + "description": "The generated-index page description for category Concepts in sidebar tutorialSidebar" + } +} diff --git a/docs/i18n/en/docusaurus-theme-classic/navbar.json b/docs/i18n/en/docusaurus-theme-classic/navbar.json new file mode 100644 index 000000000..6768c78cd --- /dev/null +++ b/docs/i18n/en/docusaurus-theme-classic/navbar.json @@ -0,0 +1,30 @@ +{ + "logo.alt": { + "message": "Site Logo", + "description": "The alt text of navbar logo" + }, + "item.label.Get Started": { + "message": "Get Started", + "description": "Navbar item with label Get Started" + }, + "item.label.About": { + "message": "About", + "description": "Navbar item with label About" + }, + "item.label.Pillars": { + "message": "Pillars", + "description": "Navbar item with label Pillars" + }, + "item.label.Utils": { + "message": "Utils", + "description": "Navbar item with label Utils" + }, + "item.label.Community": { + "message": "Community", + "description": "Navbar item with label Community" + }, + "item.label.Concepts": { + "message": "Concepts", + "description": "Navbar item with label Concepts" + } +} diff --git a/docs/i18n/es/code.json b/docs/i18n/es/code.json new file mode 100644 index 000000000..f08484b4b --- /dev/null +++ b/docs/i18n/es/code.json @@ -0,0 +1,289 @@ +{ + "theme.ErrorPageContent.title": { + "message": "Esta página ha fallado.", + "description": "The title of the fallback page when the page crashed" + }, + "theme.blog.archive.title": { + "message": "Archivar", + "description": "The page & hero title of the blog archive page" + }, + "theme.blog.archive.description": { + "message": "Archivar", + "description": "The page & hero description of the blog archive page" + }, + "theme.blog.paginator.navAriaLabel": { + "message": "Navegación de la lista de blogs", + "description": "The ARIA label for the blog pagination" + }, + "theme.blog.paginator.newerEntries": { + "message": "Entradas nuevas", + "description": "The label used to navigate to the newer blog posts page (previous page)" + }, + "theme.blog.paginator.olderEntries": { + "message": "Entradas antiguas", + "description": "The label used to navigate to the older blog posts page (next page)" + }, + "theme.BackToTopButton.buttonAriaLabel": { + "message": "Desplazar hacia arriba", + "description": "The ARIA label for the back to top button" + }, + "theme.blog.post.paginator.navAriaLabel": { + "message": "Navegación de la página del blog", + "description": "The ARIA label for the blog posts pagination" + }, + "theme.blog.post.paginator.newerPost": { + "message": "Poste más reciente", + "description": "The blog post button label to navigate to the newer/previous post" + }, + "theme.blog.post.paginator.olderPost": { + "message": "Poste antiguo", + "description": "The blog post button label to navigate to the older/next post" + }, + "theme.blog.post.plurals": { + "message": "Una publicación|{count} publicaciones", + "description": "Pluralized label for \"{count} posts\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.blog.tagTitle": { + "message": "{nPosts} etiquetado con \"{tagName}\"", + "description": "The title of the page for a blog tag" + }, + "theme.tags.tagsPageLink": { + "message": "Ver todas las etiquetas", + "description": "The label of the link targeting the tag list page" + }, + "theme.colorToggle.ariaLabel": { + "message": "Cambiar entre modo oscuro y claro (actualmente {mode})", + "description": "The ARIA label for the navbar color mode toggle" + }, + "theme.colorToggle.ariaLabel.mode.dark": { + "message": "modo oscuro", + "description": "The name for the dark color mode" + }, + "theme.colorToggle.ariaLabel.mode.light": { + "message": "modo de luz", + "description": "The name for the light color mode" + }, + "theme.docs.DocCard.categoryDescription": { + "message": "{count} objetos", + "description": "The default description for a category card in the generated index about how many items this category includes" + }, + "theme.docs.breadcrumbs.navAriaLabel": { + "message": "migas de pan", + "description": "The ARIA label for the breadcrumbs" + }, + "theme.docs.paginator.navAriaLabel": { + "message": "Páginas de documentos", + "description": "The ARIA label for the docs pagination" + }, + "theme.docs.paginator.previous": { + "message": "Anterior", + "description": "The label used to navigate to the previous doc" + }, + "theme.docs.paginator.next": { + "message": "Siguiente", + "description": "The label used to navigate to the next doc" + }, + "theme.docs.tagDocListPageTitle.nDocsTagged": { + "message": "Un documento etiquetado|{count} documentos etiquetados", + "description": "Pluralized label for \"{count} docs tagged\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.docs.tagDocListPageTitle": { + "message": "{nDocsTagged} con \"{tagName}\"", + "description": "The title of the page for a docs tag" + }, + "theme.docs.versionBadge.label": { + "message": "Versión: {versionLabel}" + }, + "theme.docs.versions.unreleasedVersionLabel": { + "message": "Esta es la documentación no publicada para la versión {siteTitle} {versionLabel}.", + "description": "The label used to tell the user that he's browsing an unreleased doc version" + }, + "theme.docs.versions.unmaintainedVersionLabel": { + "message": "Esta es la documentación para {siteTitle} {versionLabel}, que ya no se mantiene activamente.", + "description": "The label used to tell the user that he's browsing an unmaintained doc version" + }, + "theme.docs.versions.latestVersionSuggestionLabel": { + "message": "Para obtener documentación actualizada, consulte la {latestVersionLink} ({versionLabel}).", + "description": "The label used to tell the user to check the latest version" + }, + "theme.docs.versions.latestVersionLinkLabel": { + "message": "última versión", + "description": "The label used for the latest version suggestion link label" + }, + "theme.common.editThisPage": { + "message": "Editar esta página", + "description": "The link label to edit the current page" + }, + "theme.common.headingLinkTitle": { + "message": "Enlace directo a {heading}", + "description": "Title for link to heading" + }, + "theme.lastUpdated.atDate": { + "message": " en {date}", + "description": "The words used to describe on which date a page has been last updated" + }, + "theme.lastUpdated.byUser": { + "message": " por {user}", + "description": "The words used to describe by who the page has been last updated" + }, + "theme.lastUpdated.lastUpdatedAtBy": { + "message": "Última actualización{atDate}{byUser}", + "description": "The sentence used to display when a page has been last updated, and by who" + }, + "theme.NotFound.title": { + "message": "Página no encontrada", + "description": "The title of the 404 page" + }, + "theme.navbar.mobileVersionsDropdown.label": { + "message": "Versiones", + "description": "The label for the navbar versions dropdown on mobile view" + }, + "theme.tags.tagsListLabel": { + "message": "Etiquetas:", + "description": "The label alongside a tag list" + }, + "theme.AnnouncementBar.closeButtonAriaLabel": { + "message": "Cerrar", + "description": "The ARIA label for close button of announcement bar" + }, + "theme.admonition.caution": { + "message": "precaución", + "description": "The default label used for the Caution admonition (:::caution)" + }, + "theme.admonition.danger": { + "message": "peligro", + "description": "The default label used for the Danger admonition (:::danger)" + }, + "theme.admonition.info": { + "message": "info", + "description": "The default label used for the Info admonition (:::info)" + }, + "theme.admonition.note": { + "message": "nota", + "description": "The default label used for the Note admonition (:::note)" + }, + "theme.admonition.tip": { + "message": "tip", + "description": "The default label used for the Tip admonition (:::tip)" + }, + "theme.admonition.warning": { + "message": "advertencia", + "description": "The default label used for the Warning admonition (:::warning)" + }, + "theme.blog.sidebar.navAriaLabel": { + "message": "Navegación de mensajes recientes del blog", + "description": "The ARIA label for recent posts in the blog sidebar" + }, + "theme.CodeBlock.copied": { + "message": "Copiado", + "description": "The copied button label on code blocks" + }, + "theme.CodeBlock.copyButtonAriaLabel": { + "message": "Copiar código al portapapeles", + "description": "The ARIA label for copy code blocks button" + }, + "theme.CodeBlock.copy": { + "message": "Copiar", + "description": "The copy button label on code blocks" + }, + "theme.CodeBlock.wordWrapToggle": { + "message": "Cambiar envoltura de palabra", + "description": "The title attribute for toggle word wrapping button of code block lines" + }, + "theme.DocSidebarItem.expandCategoryAriaLabel": { + "message": "Expandir la categoría de barra lateral '{label}'", + "description": "The ARIA label to expand the sidebar category" + }, + "theme.DocSidebarItem.collapseCategoryAriaLabel": { + "message": "Colapsar la barra lateral categoría '{label}'", + "description": "The ARIA label to collapse the sidebar category" + }, + "theme.NavBar.navAriaLabel": { + "message": "Principal", + "description": "The ARIA label for the main navigation" + }, + "theme.NotFound.p1": { + "message": "No pudimos encontrar lo que estaba buscando.", + "description": "The first paragraph of the 404 page" + }, + "theme.NotFound.p2": { + "message": "Póngase en contacto con el propietario del sitio que le vinculó a la URL original y hágales saber que su enlace está roto.", + "description": "The 2nd paragraph of the 404 page" + }, + "theme.navbar.mobileLanguageDropdown.label": { + "message": "Idiomas", + "description": "The label for the mobile language switcher dropdown" + }, + "theme.blog.post.readMore": { + "message": "Leer más", + "description": "The label used in blog post item excerpts to link to full blog posts" + }, + "theme.blog.post.readMoreLabel": { + "message": "Lee más sobre {title}", + "description": "The ARIA label for the link to full blog posts from excerpts" + }, + "theme.blog.post.readingTime.plurals": { + "message": "Un minuto leído|{readingTime} min leídos", + "description": "Pluralized label for \"{readingTime} min read\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.docs.breadcrumbs.home": { + "message": "Página de inicio", + "description": "The ARIA label for the home page in the breadcrumbs" + }, + "theme.docs.sidebar.collapseButtonTitle": { + "message": "Colapsar barra lateral", + "description": "The title attribute for collapse button of doc sidebar" + }, + "theme.docs.sidebar.collapseButtonAriaLabel": { + "message": "Colapsar barra lateral", + "description": "The title attribute for collapse button of doc sidebar" + }, + "theme.docs.sidebar.navAriaLabel": { + "message": "Docs sidebar", + "description": "The ARIA label for the sidebar navigation" + }, + "theme.TOCCollapsible.toggleButtonLabel": { + "message": "En esta página", + "description": "The label used by the button on the collapsible TOC component" + }, + "theme.docs.sidebar.expandButtonTitle": { + "message": "Expand sidebar", + "description": "The ARIA label and title attribute for expand button of doc sidebar" + }, + "theme.docs.sidebar.expandButtonAriaLabel": { + "message": "Expand sidebar", + "description": "The ARIA label and title attribute for expand button of doc sidebar" + }, + "theme.docs.sidebar.closeSidebarButtonAriaLabel": { + "message": "Cerrar barra de navegación", + "description": "The ARIA label for close button of mobile sidebar" + }, + "theme.docs.sidebar.toggleSidebarButtonAriaLabel": { + "message": "Cambiar barra de navegación", + "description": "The ARIA label for hamburger menu button of mobile navigation" + }, + "theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel": { + "message": "← Volver al menú principal", + "description": "The label of the back button to return to main menu, inside the mobile navbar sidebar secondary menu (notably used to display the docs sidebar)" + }, + "theme.ErrorPageContent.tryAgain": { + "message": "Inténtalo de nuevo", + "description": "The label of the button to try again rendering when the React error boundary captures an error" + }, + "theme.common.skipToMainContent": { + "message": "Ir al contenido principal", + "description": "The skip to content label used for accessibility, allowing to rapidly navigate to main content with keyboard tab/enter navigation" + }, + "theme.tags.tagsPageTitle": { + "message": "Etiquetas", + "description": "The title of the tag list page" + }, + "theme.unlistedContent.title": { + "message": "Página no enumerada", + "description": "The unlisted content banner title" + }, + "theme.unlistedContent.message": { + "message": "Esta página no está en la lista. Los motores de búsqueda no lo indexarán, y sólo los usuarios que tengan un enlace directo pueden acceder a ella.", + "description": "The unlisted content banner message" + } +} diff --git a/docs/i18n/es/docusaurus-plugin-content-blog/options.json b/docs/i18n/es/docusaurus-plugin-content-blog/options.json new file mode 100644 index 000000000..7e31e5cc5 --- /dev/null +++ b/docs/i18n/es/docusaurus-plugin-content-blog/options.json @@ -0,0 +1,14 @@ +{ + "title": { + "message": "Blog", + "description": "The title for the blog used in SEO" + }, + "description": { + "message": "Blog", + "description": "The description for the blog used in SEO" + }, + "sidebar.title": { + "message": "Mensajes recientes", + "description": "The label for the left sidebar" + } +} diff --git a/docs/i18n/es/docusaurus-plugin-content-docs/current.json b/docs/i18n/es/docusaurus-plugin-content-docs/current.json new file mode 100644 index 000000000..a2f370e02 --- /dev/null +++ b/docs/i18n/es/docusaurus-plugin-content-docs/current.json @@ -0,0 +1,30 @@ +{ + "version.label": { + "message": "Siguiente", + "description": "The label for version current" + }, + "sidebar.tutorialSidebar.category.The 3 Pillars": { + "message": "Los 3 pilares", + "description": "The label for category The 3 Pillars in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.The 3 Pillars.link.generated-index.description": { + "message": "Los 3 pilares de GetX.", + "description": "The generated-index page description for category The 3 Pillars in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.Community": { + "message": "Comunidad", + "description": "The label for category Community in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.Community.link.generated-index.description": { + "message": "Comunidad.", + "description": "The generated-index page description for category Community in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.Concepts": { + "message": "Conceptos", + "description": "The label for category Concepts in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.Concepts.link.generated-index.description": { + "message": "Los conceptos sobre los 3 pilares de GetX.", + "description": "The generated-index page description for category Concepts in sidebar tutorialSidebar" + } +} diff --git a/docs/i18n/es/docusaurus-plugin-content-docs/current/about.md b/docs/i18n/es/docusaurus-plugin-content-docs/current/about.md new file mode 100644 index 000000000..c4df7f55e --- /dev/null +++ b/docs/i18n/es/docusaurus-plugin-content-docs/current/about.md @@ -0,0 +1,44 @@ +--- +sidebar_position: 2 +--- + +# Acerca de GetX + +- GetX es una solución extra ligera y potente para Flutter. Combina gestión estatal de alto rendimiento, inyección inteligente de dependencias y gestión de rutas de manera rápida y práctica. + +- GetX tiene 3 principios básicos. Esto significa que estos son la prioridad para todos los recursos de la biblioteca: **PRODUCTIVIDAD, PERFORMANCIA Y ORGANIZACIÓN.** + + - **PERFORMANCE:** GetX se centra en el rendimiento y el consumo mínimo de recursos. GetX no usa Streams o ChangeNotifier. + + - **PRODUCTIVITY:** GetX utiliza una sintaxis fácil y agradable. No importa lo que quiera hacer, siempre hay una manera más fácil con GetX. Ahorrará horas de desarrollo y proporcionará el máximo rendimiento que su aplicación puede proporcionar. + + Generalmente, el desarrollador debería preocuparse por eliminar los controladores de la memoria. Con GetX esto no es necesario porque los recursos se eliminan de la memoria cuando no son usados por defecto. Si desea conservarlo en la memoria, debe declarar explícitamente "permanente: true" en su dependencia. De esta manera, además de ahorrar tiempo, corremos menos riesgo de tener dependencias innecesarias en la memoria. La carga de dependencias también es perezosa por defecto. + + - **ORGANIZACIÓN:** GetX permite el desacoplamiento total de la Vista, lógica de presentación, lógica de negocio, inyección de dependencias y navegación. No necesita contexto para navegar entre rutas, por lo que no depende del árbol de widgets (visualización) para esto. No necesitas contexto para acceder a tus controladores/bloques a través de una herededWidget, por lo que desacoplas completamente tu lógica de presentación y lógica de negocio de tu capa de visualización. No necesita inyectar las clases Controllers/Modelos/Blocs en su árbol de widgets a través de `MultiProvider`s. Para esto, GetX utiliza su propia característica de inyección de dependencias, desacoplando el DI desde su vista completamente. + + Con GetX usted sabe dónde encontrar cada característica de su aplicación, teniendo código limpio de forma predeterminada. Además de facilitar el mantenimiento, esto hace que el intercambio de módulos sea algo que hasta entonces en Flutter era impensable, algo totalmente posible. + BLoC fue un punto de partida para organizar código en Flutter, separa la lógica de negocio de la visualización. GetX es una evolución natural de esto, no sólo separando la lógica de negocio, sino también la lógica de presentación. La inyección adicional de dependencias y rutas también se desacoplan, y la capa de datos está fuera de todo. Sabes dónde está todo y todo esto de una manera más fácil que construir un mundo feliz. + GetX es la forma más fácil, práctica y escalable de construir aplicaciones de alto rendimiento con el Flutter SDK. Tiene un gran ecosistema a su alrededor que funciona a la perfección, es fácil para los principiantes, y es preciso para los expertos. Es seguro, estable, actualizado, y ofrece una amplia gama de API integradas que no están presentes en el SDK por defecto. + +- GetX no está inflado. Tiene una multitud de características que te permiten comenzar a programar sin preocuparte de nada, pero cada una de estas características están en contenedores separados y sólo se inician después de su uso. Si sólo utiliza la Administración del Estado, sólo se compilará la Administración del Estado. Si usted sólo utiliza rutas, no se compilará nada de la gestión estatal. + +- GetX tiene un enorme ecosistema, una gran comunidad, un gran número de colaboradores, y se mantendrá mientras exista el Flutter. GetX también es capaz de ejecutarse con el mismo código en Android, iOS, Web, Mac, Linux, Windows y en su servidor. + **Es posible reutilizar completamente tu código hecho en el frontend de tu backend con [Get Server](https://github.com/jonataslaw/get_server)**. + +**Además, todo el proceso de desarrollo puede ser completamente automatizado, tanto en el servidor como en el frontal con [Obtener CLI](https://github.com/jonataslaw/get_cli)**. + +**Además, para aumentar aún más tu productividad, tenemos la +[extensión de VSCode](https://marketplace.visualstudio.com/items?itemName=get-snippets.get-snippets) y la [extensión de Android Studio/Intellij](https://plugins.jetbrains.com/plugin/14975-getx-snippets)** + +## ¿Por qué conseguir? + +1- Muchas veces después de una actualización de Flutter, muchos de sus paquetes se romperán. A veces ocurren errores de compilación, a menudo aparecen errores de los que todavía no hay respuestas, y el desarrollador necesita saber de dónde viene el error, rastrear el error, sólo entonces intente abrir un problema en el repositorio correspondiente, y vea su problema resuelto. Obtener centraliza los recursos principales para el desarrollo (gestión de rutas), permitiendo añadir un solo paquete a tu pubspec, y empezar a trabajar. Después de una actualización de Flutter, lo único que necesita hacer es actualizar la dependencia Obtener y ponerse a trabajar. Obtener también resuelve problemas de compatibilidad. Cuántas veces una versión de un paquete no es compatible con la versión de otra, porque uno usa una dependencia en una versión, y el otro en otra versión? Tampoco es una preocupación utilizar Get, ya que todo está en el mismo paquete y es totalmente compatible. + +2- Flutter es fácil, Flutter es increíble, pero Flutter todavía tiene algo de caldera que puede no ser deseado para la mayoría de los desarrolladores, como `Navigator. f(context).push (contexto, constructor [...]`. Obtener simplifica el desarrollo. En lugar de escribir 8 líneas de código para simplemente llamar a una ruta, puedes hacerlo: `Obtener. o(Home())` y listo, irás a la página siguiente. Las urls dinámicas de la web son algo realmente doloroso que ver con Flutter actualmente, y que con GetX es absurdamente simple. Gestionar estados en Flutter, y gestionar las dependencias también es algo que genera mucha discusión, ya que hay cientos de patrones en el pub. Pero no hay nada tan fácil como añadir un ". bs" al final de su variable, y colocar su widget dentro de un Obx, y eso es así, todas las actualizaciones de esa variable se actualizarán automáticamente en la pantalla. + +3- Únete sin preocuparte por el rendimiento. El rendimiento de Flutter ya es sorprendente, pero imagina que usas un administrador de estado, y un localizador para distribuir tus clases, bloques/almacenes/controladores, etc. Tendrás que llamar manualmente a la exclusión de esa dependencia cuando no la necesites. Pero ¿alguna vez has pensado en usar simplemente tu controlador, y cuando ya no estaba siendo utilizado por nadie, simplemente se borraría de la memoria? Eso es lo que hace GetX. Con SmartManagement, todo lo que no se está usando se borra de la memoria, y no debería tener que preocuparse por nada más que programar. Estarán seguros de que están consumiendo los recursos mínimos necesarios, sin ni siquiera haber creado una lógica para ello. + +4- Desacoplamiento real. Puede que haya escuchado el concepto "separar la vista de la lógica de negocio". Esto no es una pecularidad de BLoC, MVC, MVM, y cualquier otro estándar en el mercado tiene este concepto. Sin embargo, este concepto puede mitigarse a menudo en Flutter debido al uso del contexto. +Si necesita contexto para encontrar un inheritedWidget, lo necesita en la vista, o pasar el contexto por parámetro. Me parece que esta solución es muy fea, y para trabajar en equipos siempre dependeremos de la lógica empresarial de View. Getx es poco 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 APIREST por ejemplo, no depende de nada en la vista. Puede usar onInit para iniciar la llamada http, y cuando los datos llegan, las variables se llenarán. Como GetX es completamente reactivo (realmente, y funciona bajo streams), una vez que los elementos son llenados, todos los widgets que usen esa variable se actualizarán automáticamente en la vista. Esto permite a las personas con experiencia en la interfaz de usuario trabajar sólo con widgets, y no tiene que enviar nada a la lógica de negocio aparte de los eventos del usuario (como hacer clic en un botón), mientras que la gente que trabaja con la lógica de negocios será libre de crear y probar la lógica de negocio por separado. + +Esta biblioteca siempre se actualizará e implementará nuevas características. Siéntase libre de ofrecer PRs y contribuir a ellos. diff --git a/docs/i18n/es/docusaurus-plugin-content-docs/current/community/_category_.json b/docs/i18n/es/docusaurus-plugin-content-docs/current/community/_category_.json new file mode 100644 index 000000000..f9ee21e01 --- /dev/null +++ b/docs/i18n/es/docusaurus-plugin-content-docs/current/community/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "Comunidad", + "position": 10, + "link": { + "type": "índice generado", + "description": "Comunidad." + } +} diff --git a/docs/i18n/es/docusaurus-plugin-content-docs/current/community/channels.md b/docs/i18n/es/docusaurus-plugin-content-docs/current/community/channels.md new file mode 100644 index 000000000..d978b79ab --- /dev/null +++ b/docs/i18n/es/docusaurus-plugin-content-docs/current/community/channels.md @@ -0,0 +1,7 @@ +# Canales + +GetX tiene una comunidad muy activa y útil. Si tiene preguntas, o desea cualquier ayuda con respecto al uso de este marco, por favor únase a nuestros canales de la comunidad, su pregunta será respondida más rápidamente, y será el lugar más adecuado. Este repositorio es exclusivo para abrir incidencias y solicitar recursos, pero no dude en formar parte de la Comunidad GetX. + +| **Slack** | **Discord** | **Telegram** | +| :---------------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------- | +| [![Consigue Slack](https://img.shields.io/badge/slack-join-orange.svg)](https://communityinviter.com/apps/getxworkspace/getx) | [![Escudo de Discord](https://img.shields.io/discord/722900883784073290.svg?logo=discord)](https://discord.com/invite/9Hpt99N) | [![Telegram](https://img.shields.io/badge/chat-on%20Telegram-blue.svg)](https://t.me/joinchat/PhdbJRmsZNpAqSLJLJL6bH7g) | diff --git a/docs/i18n/es/docusaurus-plugin-content-docs/current/community/contribute.md b/docs/i18n/es/docusaurus-plugin-content-docs/current/community/contribute.md new file mode 100644 index 000000000..912e8ce3a --- /dev/null +++ b/docs/i18n/es/docusaurus-plugin-content-docs/current/community/contribute.md @@ -0,0 +1,11 @@ +# Cómo contribuir + +_¿Quieres contribuir al proyecto? Estaremos orgullosos de destacarle como uno de nuestros colaboradores. Aquí tienes algunos puntos donde puedes contribuir y hacer Get (y Flutter) aún mejor._ + +- Ayudando a traducir el lector a otros idiomas. +- Añadiendo documentación al léame (muchas funciones de Get aún no han sido documentadas). +- Escribe artículos o haz videos enseñando cómo usar Get (serán insertados en el Readme y en el futuro en nuestra Wiki). +- Ofreciendo PRs para código/pruebas. +- Incluye nuevas funciones. + +¡Cualquier contribución es bienvenida! diff --git a/docs/i18n/es/docusaurus-plugin-content-docs/current/community/resources.md b/docs/i18n/es/docusaurus-plugin-content-docs/current/community/resources.md new file mode 100644 index 000000000..1cbeb5ba0 --- /dev/null +++ b/docs/i18n/es/docusaurus-plugin-content-docs/current/community/resources.md @@ -0,0 +1,21 @@ +# Recursos + +### Artículos y videos + +- [Paquete EcoSystem de Getx Flutter para personas arábicas](https://www.youtube.com/playlist?list=PLV1fXIAyjeuZ6M8m56zajMUwu4uE3-SL0) - Tutorial por [Pesa Coder](https://github.com/UsamaElgendy). +- [Temas dinámicos en 3 líneas usando GetXTM](https://medium.com/swlh/flutter-dynamic-themes-in-3-lines-c3b375f292e3) - Tutorial por [Rod Brown](https://github.com/RodBr). +- [Complete GetXTM Navigation](https://www.youtube.com/watch?v=RaqPIoJSTtI) - Video de gestión de rutas por Amateur Coder. +- [Completa GetX State Management](https://www.youtube.com/watch?v=CNpXbeI_slw) - Video de gestión del estado por Amateur Coder. +- [GetXTM Otras características](https://youtu.be/ttQtlX_Q0eU) - Utils, storage, bindings and other features video by Amateur Coder. +- [Firestore User with GetX | Todo App](https://www.youtube.com/watch?v=BiV0DcXgk58) - Video por Amateur Coder. +- [Firebase Auth with GetX | Todo App](https://www.youtube.com/watch?v=-H-T_BSgfOE) - Video por Amateur Coder. +- [The Flutter GetXTM Ecosystem \~ State Management](https://medium.com/flutter-community/the-flutter-getx-ecosystem-state-management-881c7235511d) - Gestión estatal por [Aachman Garg](https://github.com/imaachman). +- [The Flutter GetXTM Ecosystem \~ Dependency Injection](https://medium.com/flutter-community/the-flutter-getx-ecosystem-dependency-injection-8e763d0ec6b9) - Inyección de dependencias por [Aachman Garg](https://github.com/imaachman). +- [GetX, el paquete todo en uno Flutter](https://www.youtube.com/watch?v=IYQgtu9TM74) - Un breve tutorial sobre Administración del Estado y Navegación por Thad Carnevalli. +- [Construye una lista de tareas desde cero usando Flutter y GetX](https://www.youtube.com/watch?v=EcnqFasHf18) - UI + Administración del Estado + vídeo de almacenamiento por Thad Carnevalli. +- [Ejemplo Auth de GetX Flutter Firebase](https://medium.com/@jeffmcmorris/getx-flutter-firebase-auth-example-b383c1dd1de2) - Artículo por Jeff McMorris. +- [Flutter State Management with GetX – Complete App](https://www.appwithflutter.com/flutter-state-management-with-getx/) - por App With Flutter. +- [Ruta de Flutter con Animación usando Get Package](https://www.appwithflutter.com/flutter-routing-using-get-package/) - por App With Flutter. +- [¿Un ejemplo mínimo en dartpad](https://dartpad.dev/2b3d0d6f9d4e312c5fdbefc414c1727e?) - por [Roi Peker](https://github.com/roipeker) +- [GetConnect: La mejor manera de realizar operaciones API en Flutter con Get.](https://absyz.com/getconnect-the-best-way-to-perform-api-operations-in-flutter-with-getx/) - por [MD Sarfaraj](https://github.com/socialmad) +- [Cómo crear una aplicación con GetX Architect in Flutter con Obtener CLI](https://www.youtube.com/watch?v=7mb4qBA7kTk\&t=1380s) - por [MD Sarfaraj](https://github.com/socialmad) diff --git a/docs/i18n/es/docusaurus-plugin-content-docs/current/concepts/_category_.json b/docs/i18n/es/docusaurus-plugin-content-docs/current/concepts/_category_.json new file mode 100644 index 000000000..5689a9e0d --- /dev/null +++ b/docs/i18n/es/docusaurus-plugin-content-docs/current/concepts/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "Conceptos", + "position": 3, + "link": { + "type": "índice generado", + "description": "Los conceptos sobre los 3 pilares de GetX." + } +} diff --git a/docs/i18n/es/docusaurus-plugin-content-docs/current/concepts/dependency-management.md b/docs/i18n/es/docusaurus-plugin-content-docs/current/concepts/dependency-management.md new file mode 100644 index 000000000..8a3e554b5 --- /dev/null +++ b/docs/i18n/es/docusaurus-plugin-content-docs/current/concepts/dependency-management.md @@ -0,0 +1,39 @@ +--- +sidebar_position: 3 +--- + +# Gestión de dependencias + +Get tiene un gestor de dependencias simple y potente que te permite recuperar la misma clase que tu Bloc o Controlador con solo 1 línea de código, sin contexto de proveedores, sin inheritedWidget: + +```dart +Controller controller = Get.put(Controller()); // Rather Controller controller = Controller(); +``` + +- Nota: Si está usando Get's State Manager, preste más atención a la API de enlaces, lo que hará más fácil conectar tu vista a tu controlador. + +En lugar de instanciar su clase dentro de la clase que está usando, lo instancias dentro de la instancia Obténgala, que lo hará disponible a través de tu aplicación. +Así que puede utilizar su controlador (o bloque de clase) normalmente + +**Consejo:** Obtener la gestión de dependencias está desacoplado de otras partes del paquete, así que, si por ejemplo, tu aplicación ya está usando un administrador de estado (cualquier otro, no importa), no necesitas reescribirlo todo, puedes usar esta inyección de dependencias sin ningún problema + +```dart +controller.fetchApi(); +``` + +Imagina que has navegado a través de numerosas rutas, y necesitas datos que quedaron atrás en tu controlador, Necesitaría un administrador estatal combinado con el Proveedor o Get\_it, ¿correcto? No con obtener. Sólo necesitas preguntar Get to "encontrd" para tu controlador, no necesitas ninguna dependencia adicional: + +```dart +Controller controller = Get.find(); +//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. +``` + +Y entonces podrás recuperar los datos de tu controlador que se obtuvieron de vuelta allí: + +```dart +Text(controller.textFromApi); +``` + +### Más detalles sobre la gestión de dependencias + +**Ver una explicación más detallada de la gestión de dependencias [here](/docs/pillars/dependency-management)** diff --git a/docs/i18n/es/docusaurus-plugin-content-docs/current/concepts/route-management.md b/docs/i18n/es/docusaurus-plugin-content-docs/current/concepts/route-management.md new file mode 100644 index 000000000..d7e219bd2 --- /dev/null +++ b/docs/i18n/es/docusaurus-plugin-content-docs/current/concepts/route-management.md @@ -0,0 +1,53 @@ +--- +sidebar_position: 2 +--- + +# Gestión de rutas + +Si vas a usar rutas/barras/barrashacas/diálogo/hojas de abajo sin contexto, GetX es excelente para ti también, solo verlo: + +Añade "Obtener" antes de tu MaterialApp, convirtiéndola en GetMaterialApp + +```dart +GetMaterialApp( // Before: MaterialApp( + home: MyHome(), +) +``` + +Navegar a una nueva pantalla: + +```dart + +Get.to(NextScreen()); +``` + +Navega a la nueva pantalla con nombre. Ver más detalles sobre rutas con nombre [here](/docs/pillars/route-management#navigation-with-named-routes) + +```dart + +Get.toNamed('/details'); +``` + +Para cerrar barras de rejillas, diálogos, hojas de fondo, o cualquier cosa que normalmente cierre con Navigator.pop(context); + +```dart +Get.back(); +``` + +Para ir a la siguiente pantalla y no hay opción para volver a la pantalla anterior (para uso en SplashScreens, pantallas de inicio de sesión, etc.) + +```dart +Get.off(NextScreen()); +``` + +Para ir a la siguiente pantalla y cancelar todas las rutas anteriores (útil en carritos de la compra, encuestas y pruebas) + +```dart +Get.offAll(NextScreen()); +``` + +¿Has notado que no tienes que usar contexto para hacer ninguna de estas cosas? Esta es una de las mayores ventajas de usar Get route manager. Con esto, puede ejecutar todos estos métodos desde la clase de su controlador, sin preocuparse. + +### Más detalles sobre la gestión de rutas + +**¡Hazte trabajar con rutas con nombre y también ofrece un control de bajo nivel sobre tus rutas! Hay documentación en profundidad [here](/docs/pillars/route-management)** diff --git a/docs/i18n/es/docusaurus-plugin-content-docs/current/concepts/state-management.md b/docs/i18n/es/docusaurus-plugin-content-docs/current/concepts/state-management.md new file mode 100644 index 000000000..cacaee29c --- /dev/null +++ b/docs/i18n/es/docusaurus-plugin-content-docs/current/concepts/state-management.md @@ -0,0 +1,47 @@ +--- +sidebar_position: 1 +--- + +# Gestión del estado + +Get tiene dos administradores de estado diferentes: el simple administrador de estado (lo llamaremos GetBuilder) y el administrador de estado reactivo (GetX/Obx) + +### Gestor de estado reactivo + +La programación reactiva puede alienar a mucha gente porque se dice que es complicada. GetX convierte la programación reactiva en algo bastante simple: + +- No necesitará crear StreamControllers. +- No necesitará crear un StreamBuilder para cada variable +- No necesitará crear una clase para cada estado. +- No necesitará crear un get para un valor inicial. +- No necesitará utilizar generadores de código + +Programación reactiva con Get es tan fácil como usar setState. + +Imaginemos que tienes una variable de nombre y queremos que cada vez que la cambies, todos los widgets que la usan se cambien automáticamente. + +Esta es tu variable de contador: + +```dart +var name = 'Jonatas Borges'; +``` + +Para hacerla observable, sólo tienes que añadir ".obs" al final de la misma: + +```dart +var name = 'Jonatas Borges'.obs; +``` + +Y en la interfaz de usuario, cuando quieras mostrar ese valor y actualizar la pantalla siempre que cambien los valores, simplemente haz esto: + +```dart +Obx(() => Text("${controller.name}")); +``` + +Eso es todo. Es _simple_ simple. + +### Más detalles sobre la gestión del estado + +**Ver una explicación más detallada de la gestión del estado \[here]\(/docs/pilars/gestión del estado). Allí verá más ejemplos y también la diferencia entre el gestor de estado simple y el administrador de estado reactivo** + +Tendrás una buena idea de la potencia de GetX. diff --git a/docs/i18n/es/docusaurus-plugin-content-docs/current/intro.md b/docs/i18n/es/docusaurus-plugin-content-docs/current/intro.md new file mode 100644 index 000000000..96441e57b --- /dev/null +++ b/docs/i18n/es/docusaurus-plugin-content-docs/current/intro.md @@ -0,0 +1,94 @@ +--- +sidebar_position: 1 +--- + +# Empezar + +## Pruebas + +### Instalando + +Añade a tu archivo pubspec.yaml: + +```yml +dependencies: + get: +``` + +Importar los archivos que se utilizarán: + +```dart +import 'package:get/get.dart'; +``` + +### Contador de aplicación con GetX + +El proyecto "contador" creado por defecto en el nuevo proyecto en Flutter tiene más de 100 líneas (con comentarios). Para mostrar el poder de Get, demostraré cómo hacer un "contador" cambiando el estado con cada clic, cambiando entre páginas y compartiendo el estado entre pantallas, todo de una manera organizada, separando la lógica de negocio de la vista, en SOLO 26 LÍNEAS CÓDIGO INCLUDIANDO COMMENTES. + +- Paso 1: + Añade "Get" antes de tu MaterialApp, convirtiéndola en GetMaterialApp + +```dart +void main() => runApp(GetMaterialApp(home: Home())); +``` + +- Nota: esto no modifica la aplicación MaterialApp de Flutter, GetMaterialApp no es una aplicación MaterialApp modificada es sólo un Widget preconfigurado, que tiene como hijo el MaterialApp predeterminado. Puede configurar esto manualmente, pero definitivamente no es necesario. GetMaterialApp creará rutas, inyectarlas, inyectar traducciones, inyectar todo lo necesario para la navegación por ruta. Si utiliza Get sólo para la administración del estado o la gestión de dependencias, no es necesario utilizar GetMaterialApp. GetMaterialApp es necesario para rutas, snackbars, internacionalización, bottomSheets, diálogos y apis de alto nivel relacionados con rutas y ausencia de contexto. + +- Nota2: Este paso sólo es necesario si usted gonna usa la gestión de rutas (`Get.to()`, `Get.back()` y así sucesivamente). Si no lo usas no es necesario hacer el paso 1 + +- Paso 2: + Crea tu clase lógica de negocio y coloca todas las variables, métodos y controladores dentro de ella. + Puede hacer cualquier variable observable usando un simple ".obs". + +```dart +class Controller extends GetxController{ + var count = 0.obs; + increment() => count++; +} +``` + +- Paso 3: + Crea tu Vista, usa StatelessWidget y guarda algo de RAM, con Get puedes dejar de usar StatefulWidget. + +```dart +class Home extends StatelessWidget { + + @override + Widget build(context) { + + // Instantiate your class using Get.put() to make it available for all "child" routes there. + final Controller c = Get.put(Controller()); + + return Scaffold( + // Use Obx(()=> to update Text() whenever count is changed. + appBar: AppBar(title: Obx(() => Text("Clicks: ${c.count}"))), + + // Replace the 8 lines Navigator.push by a simple Get.to(). You don't need context + body: Center(child: ElevatedButton( + child: Text("Go to Other"), onPressed: () => Get.to(Other()))), + floatingActionButton: + FloatingActionButton(child: Icon(Icons.add), onPressed: c.increment)); + } +} + +class Other extends StatelessWidget { + // You can ask Get to find a Controller that is being used by another page and redirect you to it. + final Controller c = Get.find(); + + @override + Widget build(context){ + // Access the updated count variable + return Scaffold(body: Center(child: Text("${c.count}"))); + } +} +``` + +Resultado: + +![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/counter-app-gif.gif) + +Este es un proyecto sencillo pero ya deja claro lo poderoso que es Get . A medida que tu proyecto crece, esta diferencia será más significativa. + +Get fue diseñado para trabajar con equipos, pero hace el trabajo de un desarrollador individual simple. + +Mejore sus plazos, entregue todo a tiempo sin perder el rendimiento. Get is not for everyone, but if you identified with that phrase, Get is for you! diff --git a/docs/i18n/es/docusaurus-plugin-content-docs/current/pillars/_category_.json b/docs/i18n/es/docusaurus-plugin-content-docs/current/pillars/_category_.json new file mode 100644 index 000000000..88897199b --- /dev/null +++ b/docs/i18n/es/docusaurus-plugin-content-docs/current/pillars/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "Los 3 pilares", + "position": 3, + "link": { + "type": "índice generado", + "description": "Los 3 pilares de GetX." + } +} diff --git a/docs/i18n/es/docusaurus-plugin-content-docs/current/pillars/dependency-management.md b/docs/i18n/es/docusaurus-plugin-content-docs/current/pillars/dependency-management.md new file mode 100644 index 000000000..f1af2b2a1 --- /dev/null +++ b/docs/i18n/es/docusaurus-plugin-content-docs/current/pillars/dependency-management.md @@ -0,0 +1,404 @@ +--- +sidebar_position: 3 +--- + +# Dependencia + +Get tiene un gestor de dependencias simple y potente que te permite recuperar la misma clase que tu Bloc o Controlador con solo 1 línea de código, sin contexto de proveedores, sin inheritedWidget: + +```dart +Controller controller = Get.put(Controller()); // Rather Controller controller = Controller(); +``` + +En lugar de instanciar su clase dentro de la clase que está usando, lo instancias dentro de la instancia Obténgala, que lo hará disponible a través de tu aplicación. +Así que puedes usar tu controlador (o clase Bloc) normalmente + +- Nota: Si estás usando Get's State Manager, presta más atención a la app [Bindings](#bindings), lo que hará más fácil conectar tu vista a tu controlador. +- Nota2: Obtener la gestión de dependencias es desglosado de otras partes del paquete, así que si por ejemplo tu aplicación ya está usando un administrador de estado (cualquier otro, no importa), no necesitas cambiar eso, puedes usar este gestor de inyección de dependencias sin ningún problema + +## Métodos de Instancia + +Los métodos y sus parámetros configurables son: + +### Get.put() + +La forma más común de insertar una dependencia. Bueno para los controladores de tus vistas, por ejemplo. + +```dart +Get.put(SomeClass()); +Get.put(LoginController(), permanent: true); +Get.put(ListItemController, tag: "some unique string"); +``` + +Esto es todas las opciones que se pueden establecer al usar put: + +```dart +Get.put( + // mandatory: the class that you want to get to save, like a controller or anything + // note: "S" means that it can be a class of any type + S dependency + + // optional: this is for when you want multiple classess that are of the same type + // since you normally get a class by using Get.find(), + // you need to use tag to tell which instance you need + // must be unique string + String tag, + + // optional: by default, get will dispose instances after they are not used anymore (example, + // the controller of a view that is closed), but you might need that the instance + // to be kept there throughout the entire app, like an instance of sharedPreferences or something + // so you use this + // defaults to false + bool permanent = false, + + // optional: allows you after using an abstract class in a test, replace it with another one and follow the test. + // defaults to false + bool overrideAbstract = false, + + // optional: allows you to create the dependency using function instead of the dependency itself. + // this one is not commonly used + InstanceBuilderCallback builder, +) +``` + +### Get.lazyPut + +Es posible lazyLoad una dependencia para que se instancie sólo cuando se use. Muy útil para clases caras computacionales o si desea instanciar varias clases en un solo lugar (como en una clase Bindings) y sabe que no va a utilizar esa clase en ese momento. + +```dart +/// ApiMock will only be called when someone uses Get.find for the first time +Get.lazyPut(() => ApiMock()); + +Get.lazyPut( + () { + // ... some logic if needed + return FirebaseAuth(); + }, + tag: Math.random().toString(), + fenix: true +) + +Get.lazyPut( () => Controller() ) +``` + +Esta es todas las opciones que puedes establecer al usar lazyPut: + +```dart +Get.lazyPut( + // mandatory: a method that will be executed when your class is called for the first time + InstanceBuilderCallback builder, + + // optional: same as Get.put(), it is used for when you want multiple different instance of a same class + // must be unique + String tag, + + // optional: It is similar to "permanent", the difference is that the instance is discarded when + // is not being used, but when it's use is needed again, Get will recreate the instance + // just the same as "SmartManagement.keepFactory" in the bindings api + // defaults to false + bool fenix = false + +) +``` + +### Get.putAsync + +Si desea registrar una instancia asíncrona, puede utilizar `Get.putAsync`: + +```dart +Get.putAsync(() async { + final prefs = await SharedPreferences.getInstance(); + await prefs.setInt('counter', 12345); + return prefs; +}); + +Get.putAsync( () async => await YourAsyncClass() ) +``` + +Esto es todas las opciones que se pueden establecer cuando se utiliza putAsync: + +```dart +Get.putAsync( + + // mandatory: an async method that will be executed to instantiate your class + AsyncInstanceBuilderCallback builder, + + // optional: same as Get.put(), it is used for when you want multiple different instance of a same class + // must be unique + String tag, + + // optional: same as in Get.put(), used when you need to maintain that instance alive in the entire app + // defaults to false + bool permanent = false +) +``` + +### Get.create + +Este es complicado. Una explicación detallada de lo que es esto y de las diferencias entre el otro se puede encontrar en la sección [Diferencias entre métodos:](#differences-between-methods) + +```dart +Get.Create(() => SomeClass()); +Get.Create(() => LoginController()); +``` + +Estas son todas las opciones que puedes establecer al usar create: + +```dart +Get.create( + // required: a function that returns a class that will be "fabricated" every + // time `Get.find()` is called + // Example: Get.create(() => YourClass()) + FcBuilderFunc builder, + + // optional: just like Get.put(), but it is used when you need multiple instances + // of a of a same class + // Useful in case you have a list that each item need it's own controller + // needs to be a unique string. Just change from tag to name + String name, + + // optional: just like int`Get.put()`, it is for when you need to keep the + // instance alive thoughout the entire app. The difference is in Get.create + // permanent is true by default + bool permanent = true +``` + +## Usando métodos/clases instanciadas + +Imagina que has navegado a través de numerosas rutas, y necesitas un dato que se haya dejado atrás en tu controlador, Necesitaría un administrador estatal combinado con el Proveedor o Get\_it, ¿correcto? No con obtener. Sólo necesitas preguntar Get to "encontrd" para tu controlador, no necesitas ninguna dependencia adicional: + +```dart +final controller = Get.find(); +// OR +Controller controller = Get.find(); + +// 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. +``` + +Y entonces podrás recuperar los datos de tu controlador que se obtuvieron de vuelta allí: + +```dart +Text(controller.textFromApi); +``` + +Dado que el valor devuelto es una clase normal, puedes hacer lo que quieras: + +```dart +int count = Get.find().getInt('counter'); +print(count); // out: 12345 +``` + +Para remover una instancia de Get: + +```dart +Get.delete(); //usually you don't need to do this because GetX already delete unused controllers +``` + +## Especificar una instancia alternativa + +Una instancia actualmente insertada puede ser reemplazada con una instancia de clase similar o extendida usando el método `replace` o `lazyReplace`. Esto puede ser recuperado usando la clase original. + +```dart +abstract class BaseClass {} +class ParentClass extends BaseClass {} + +class ChildClass extends ParentClass { + bool isChild = true; +} + + +Get.put(ParentClass()); + +Get.replace(ChildClass()); + +final instance = Get.find(); +print(instance is ChildClass); //true + + +class OtherClass extends BaseClass {} +Get.lazyReplace(() => OtherClass()); + +final instance = Get.find(); +print(instance is ChildClass); // false +print(instance is OtherClass); //true +``` + +## Diferencias entre métodos + +Primero, vamos al "fenix" de Get.lazyPut y al "permanente" de los otros métodos. + +La diferencia fundamental entre `permanent` y `fenix` es cómo quieres almacenar tus instancias. + +Refuerzo: por defecto, GetX elimina las instancias cuando no están en uso. +Significa que: Si la pantalla 1 tiene el controlador 1 y la pantalla 2 tiene el controlador 2 y se quita la primera ruta de la pila, (como si usas `Obtener. ff()` o `Get.offNamed()`) el controlador 1 perdió su uso por lo que será borrado. + +Pero si quieres optar por usar `permanent:true`, entonces el controlador no se perderá en esta transición - que es muy útil para los servicios que desea mantener vivo a lo largo de toda la aplicación. + +`fenix` en la otra mano es para servicios que no te preocupas al perder entre los cambios de pantalla, pero cuando usted necesita ese servicio, usted espera que esté vivo. Básicamente, dispondrá el controlador/servicio/clase/clase no utilizado, pero cuando lo necesite, "recreará desde las ashes" una nueva instancia. + +Continuando con las diferencias entre métodos: + +- Get.put y Get. utAsync sigue el mismo orden de creación, con la diferencia de que el segundo utiliza un método asíncrono: esos dos métodos crean e inicializan la instancia. Que uno se inserta directamente en la memoria, usando el método interno `insert` con los parámetros `permanente: false` y `isSingleton: true` (este parámetro isSingleton sólo tiene el propósito de indicar si es para usar la dependencia de `dependency` o si es para usar la dependencia de `FcBuilderFunc`). Después de eso, `Get.find()` es llamado que inmediatamente inicializa las instancias que están en memoria. + +- Get.create: ¡Como su nombre lo implica, "creará" su dependencia! Similar a `Get.put()`, también llama al método interno `insert` para instanciar. Pero `permanent` se hizo cierto y `isSingleton` se volvió falso (ya que estamos "creando" nuestra dependencia, no hay manera de que sea una instancia singleton, por eso es falso). Y porque tiene `permanente: true`, tenemos por defecto el beneficio de no perderlo entre las pantallas! Además, `Get.find()` no se llama inmediatamente, espera a ser usado en la pantalla para ser llamado. Se crea de esta manera para hacer uso del parámetro `permanent`, desde entonces, vale la pena observar, `Obtener. reate()` se hizo con el objetivo de crear instancias no compartidas, pero no eliminar, como por ejemplo un botón en una listView, que desea una instancia única para esa lista - por eso, Obtener. reate debe ser utilizado junto con GetWidget. + +- Get.lazyPut: Como su nombre implica, es un proceso perezoso. La instancia es creada, pero no es llamada para ser utilizada inmediatamente, permanece esperando a ser llamada. Contrario a los otros métodos, `insert` no es llamado aquí. En su lugar, la instancia se inserta en otra parte de la memoria, una parte responsable de decir si la instancia puede ser recreada o no, llamémosla "fábrica". Si queremos crear algo que se utilice más tarde, no se mezclará con las cosas que se han utilizado en este momento. Y aquí es donde entra la magia de `fenix`: si optas por dejar `fenix: false`, y tu `smartManagement` no son `keepFactory`, entonces cuando usas `Get. ind` la instancia cambiará el lugar en la memoria de la "fábrica" al área de memoria de instancia común. Justo después de eso, por defecto se elimina de la "fábrica". Ahora, si optas por `fenix: true`, la instancia sigue existiendo en esta parte dedicada, ir incluso al espacio común para ser llamado de nuevo en el futuro. + +## Enlaces + +Una de las grandes diferencias de este paquete, tal vez, es la posibilidad de la plena integración de las rutas, el administrador del estado y el gestor de dependencias. +Cuando una ruta es removida de la pila, todos los controladores, variables e instancias de objetos relacionados con ella son removidos de la memoria. Si está usando secuencias o temporizadores, se cerrarán automáticamente, y no tiene que preocuparse por nada de eso. +En la versión 2.10 Obtenga la implementación completa de la API Bindings. +Ahora ya no necesita utilizar el método init. Ni siquiera tienes que escribir tus controladores si no quieres. Puedes iniciar tus controladores y servicios en el lugar apropiado para ello. +La clase Binding es una clase que desacoplará la inyección de dependencias, mientras que las rutas "vinculantes" al administrador de estado y al gestor de dependencias. +Esto le permite a Get saber qué pantalla se muestra cuando se utiliza un controlador en particular y saber dónde y cómo eliminarlo. +Además, la clase Binding le permitirá tener el control de configuración de SmartManager. Puede configurar las dependencias a organizar al eliminar una ruta de la pila, o cuando el widget que lo usó está dispuesto, o ninguna de las dos. Tendrás una gestión inteligente de dependencias trabajando para ti, pero aún así, puedes configurarla como quieras. + +### Clase de enlaces + +- Crear una clase e implementa Binding + +```dart +class HomeBinding implements Bindings {} +``` + +Su IDE automáticamente le pedirá que reemplace el método "dependencias" y sólo necesita hacer clic en la lámpara, sobreescribir el método, e insertar todas las clases que va a utilizar en esa ruta: + +```dart +class HomeBinding implements Bindings { + @override + void dependencies() { + Get.lazyPut(() => HomeController()); + Get.put(()=> Api()); + } +} + +class DetailsBinding implements Bindings { + @override + void dependencies() { + Get.lazyPut(() => DetailsController()); + } +} +``` + +Ahora sólo necesita informar a su ruta, que utilizará ese enlace para hacer la conexión entre el gestor de rutas, las dependencias y los estados. + +- Usando rutas nombradas: + +```dart +getPages: [ + GetPage( + name: '/', + page: () => HomeView(), + binding: HomeBinding(), + ), + GetPage( + name: '/details', + page: () => DetailsView(), + binding: DetailsBinding(), + ), +]; +``` + +- Usando rutas normales: + +```dart +Get.to(Home(), binding: HomeBinding()); +Get.to(DetailsView(), binding: DetailsBinding()) +``` + +Allí, ya no tienes que preocuparte por la administración de memoria de tu aplicación. Get lo hará por ti. + +La clase Binding es llamada cuando se llama a una ruta, puedes crear un "initialBinding en tu GetMaterialApp para insertar todas las dependencias que se crearán. + +```dart +GetMaterialApp( + initialBinding: SampleBind(), + home: Home(), +); +``` + +### Constructor de enlaces + +La forma predeterminada de crear un enlace es creando una clase que implemente Bindings. +Pero alternativamente, puedes usar el callback `BindingsBuilder` para que puedas simplemente usar una función para instanciar lo que desees. + +Ejemplo: + +```dart +getPages: [ + GetPage( + name: '/', + page: () => HomeView(), + binding: BindingsBuilder(() { + Get.lazyPut(() => ControllerX()); + Get.put(()=> Api()); + }), + ), + GetPage( + name: '/details', + page: () => DetailsView(), + binding: BindingsBuilder(() { + Get.lazyPut(() => DetailsController()); + }), + ), +]; +``` + +De esta manera puede evitar crear una clase Binding para cada ruta, haciendo esto aún más sencillo. + +Ambas formas de trabajar perfectamente y queremos que usted utilice lo que más se adapte a sus gustos. + +### Gestión inteligente + +GetX por defecto dispone de controladores no utilizados de la memoria, incluso si ocurre un fallo y un widget que lo usa no está correctamente eliminado. +Esto es lo que se llama el modo 'completo' de gestión de dependencias. +Pero si quieres cambiar la forma en que GetX controla la eliminación de clases, tienes la clase `SmartManagement` que puedes establecer diferentes comportamientos. + +#### Cómo cambiar + +Si desea cambiar esta configuración (que normalmente no necesita) esta es la manera: + +```dart +void main () { + runApp( + GetMaterialApp( + smartManagement: SmartManagement.onlyBuilder //here + home: Home(), + ) + ) +} +``` + +#### SmartManagement.full + +Es el predeterminado. Descartar las clases que no están siendo usadas y que no están configuradas como permanentes. En la mayoría de los casos querrá mantener esta configuración sin tocar. Si usted es nuevo en GetX entonces no cambie esto. + +#### SmartManagement.onlyBuilder + +Con esta opción, sólo se eliminarán los controladores iniciados en `init:` o cargados en un enlace con `Get.lazyPut()`. + +Si utiliza `Get.put()` o `Get.putAsync()` o cualquier otro enfoque, SmartManagement no tendrá permisos para excluir esta dependencia. + +Con el comportamiento por defecto, incluso los widgets instanciados con "Get.put" serán eliminados, a diferencia de SmartManagement.onlyBuilder. + +#### SmartManagement.keepFactory + +Al igual que SmartManagement.full, eliminará sus dependencias cuando ya no se esté usando. Sin embargo, mantendrá su fábrica, lo que significa que recreará la dependencia si se necesita esa instancia de nuevo. + +### Cómo funcionan los enlaces bajo el capó + +Los enlaces crean fábricas de transitorio, que se crean en el momento en que hace clic para ir a otra pantalla, y será destruido tan pronto como ocurra la animación de cambio de pantalla. +Esto sucede tan rápido que el analizador ni siquiera será capaz de registrarlo. +Cuando navega a esta pantalla de nuevo, se llamará a una nueva fábrica temporal, por lo que es preferible usar SmartManagement. eepFactory, pero si no quieres crear enlaces, o quieres mantener todas tus dependencias en el mismo enlace, seguramente te ayudará. +Las fábricas ocupan poca memoria, no guardan las instancias, sino una función con la "forma" de la clase que quieras. +Esto tiene un costo muy bajo en la memoria, pero dado que el propósito de esta librería es obtener el máximo rendimiento posible utilizando los recursos mínimos, Obtener elimina incluso las fábricas de forma predeterminada. +Utilice el que más le convenga. + +## Notas + +- NO USE SmartManagement.keepFactory si está utilizando múltiples enlaces. Ha sido diseñado para ser utilizado sin enlaces, o con un solo enlazado en el initialBinding de GetMaterialApp. + +- Usar enlaces es completamente opcional, si lo deseas, puedes usar `Get.put()` y `Get.find()` en clases que usan un controlador dado sin ningún problema. + Sin embargo, si usted trabaja con Servicios o cualquier otra abstracción, recomiendo usar Bindings para una mejor organización. diff --git a/docs/i18n/es/docusaurus-plugin-content-docs/current/pillars/route-management.md b/docs/i18n/es/docusaurus-plugin-content-docs/current/pillars/route-management.md new file mode 100644 index 000000000..e7eda7160 --- /dev/null +++ b/docs/i18n/es/docusaurus-plugin-content-docs/current/pillars/route-management.md @@ -0,0 +1,560 @@ +--- +sidebar_position: 2 +--- + +# Ruta + +Esta es la explicación completa de todo lo que hay para Getx cuando el asunto es la gestión de rutas. + +## Cómo usar + +Añade esto a tu archivo pubspec.yaml: + +```yaml +dependencies: + get: +``` + +Si va a usar rutas/barras/barras/diálogo/hojas de abajo sin contexto, o utilizar las APIs de alto nivel, tienes que simplemente añadir "Get" antes de tu MaterialApp, convirtiéndola en GetMaterialApp y disfrutar! + +```dart +GetMaterialApp( // Before: MaterialApp( + home: MyHome(), +) +``` + +## Navegación sin rutas con nombre + +Para navegar a una nueva pantalla: + +```dart +Get.to(NextScreen()); +``` + +Para cerrar barras de rejillas, diálogos, hojas de fondo, o cualquier cosa que normalmente cierre con Navigator.pop(context); + +```dart +Get.back(); +``` + +Para ir a la siguiente pantalla y no hay opción para volver a la pantalla anterior (para uso en SplashScreens, pantallas de inicio de sesión y etc.) + +```dart +Get.off(NextScreen()); +``` + +Para ir a la siguiente pantalla y cancelar todas las rutas anteriores (útil en carritos de la compra, encuestas y pruebas) + +```dart +Get.offAll(NextScreen()); +``` + +Para navegar a la siguiente ruta, y recibir o actualizar los datos tan pronto como regrese de él: + +```dart +var data = await Get.to(Payment()); +``` + +en otra pantalla, enviar datos para la ruta anterior: + +```dart +Get.back(result: 'success'); +``` + +Y úsalo: + +ex: + +```dart +if(data == 'success') madeAnything(); +``` + +¿No quieres aprender nuestra sintaxis? +Simplemente cambia el Navigator (mayúsculas) a navegador (minúsculas), y tendrá todas las funciones de la navegación estándar, sin tener que utilizar el contexto +Ejemplo: + +```dart + +// Default Flutter navigator +Navigator.of(context).push( + context, + MaterialPageRoute( + builder: (BuildContext context) { + return HomePage(); + }, + ), +); + +// Get using Flutter syntax without needing context +navigator.push( + MaterialPageRoute( + builder: (_) { + return HomePage(); + }, + ), +); + +// Get syntax (It is much better, but you have the right to disagree) +Get.to(HomePage()); + + +``` + +## Navegación con rutas con nombre + +- Si prefiere navegar por namedRoutes, Get también soporta esto. + +Para navegar a la siguiente pantalla + +```dart +Get.toNamed("/NextScreen"); +``` + +Para navegar y quitar la pantalla anterior del árbol. + +```dart +Get.offNamed("/NextScreen"); +``` + +Para navegar y eliminar todas las pantallas anteriores del árbol. + +```dart +Get.offAllNamed("/NextScreen"); +``` + +Para definir rutas, utilice GetMaterialApp: + +```dart +void main() { + runApp( + GetMaterialApp( + initialRoute: '/', + getPages: [ + GetPage(name: '/', page: () => MyHomePage()), + GetPage(name: '/second', page: () => Second()), + GetPage( + name: '/third', + page: () => Third(), + transition: Transition.zoom + ), + ], + ) + ); +} +``` + +Para manejar la navegación a rutas no definidas (error 404), puede definir una página desconocida en GetMaterialApp. + +```dart +void main() { + runApp( + GetMaterialApp( + unknownRoute: GetPage(name: '/notfound', page: () => UnknownRoutePage()), + initialRoute: '/', + getPages: [ + GetPage(name: '/', page: () => MyHomePage()), + GetPage(name: '/second', page: () => Second()), + ], + ) + ); +} +``` + +### Enviar datos a rutas nombradas + +Envía lo que quieras para los argumentos. Obtén cualquier cosa aquí, ya sea una cadena, un mapa, una lista o incluso una instancia de clase. + +```dart +Get.toNamed("/NextScreen", arguments: 'Get is the best'); +``` + +en tu clase o controlador: + +```dart +print(Get.arguments); +//print out: Get is the best +``` + +### Enlaces de urls dinámicos + +Obtenga urls dinámicas avanzadas como en la Web. Probablemente los desarrolladores web ya han querido esta característica en Flutter, y lo más probable es que hayan visto una promesa de paquete esta característica y entregado una sintaxis totalmente diferente de la que tendría una URL en la web, pero Obtener también resuelve eso. + +```dart +Get.offAllNamed("/NextScreen?device=phone&id=354&name=Enzo"); +``` + +en tu clase controlador/bloque/stateful/stateless : + +```dart +print(Get.parameters['id']); +// out: 354 +print(Get.parameters['name']); +// out: Enzo +``` + +También puedes recibir NamedParameters con facilidad: + +```dart +void main() { + runApp( + GetMaterialApp( + initialRoute: '/', + getPages: [ + GetPage( + name: '/', + page: () => MyHomePage(), + ), + GetPage( + name: '/profile/', + page: () => MyProfile(), + ), + //You can define a different page for routes with arguments, and another without arguments, but for that you must use the slash '/' on the route that will not receive arguments as above. + GetPage( + name: '/profile/:user', + page: () => UserProfile(), + ), + GetPage( + name: '/third', + page: () => Third(), + transition: Transition.cupertino + ), + ], + ) + ); +} +``` + +Enviar datos al nombre de ruta + +```dart +Get.toNamed("/profile/34954"); +``` + +En la segunda pantalla tomar los datos por parámetro + +```dart +print(Get.parameters['user']); +// out: 34954 +``` + +o enviar múltiples parámetros como este + +```dart +Get.toNamed("/profile/34954?flag=true&country=italy"); +``` + +o + +```dart +var parameters = {"flag": "true","country": "italy",}; +Get.toNamed("/profile/34954", parameters: parameters); +``` + +En la segunda pantalla tomar los datos por parámetros como normalmente + +```dart +print(Get.parameters['user']); +print(Get.parameters['flag']); +print(Get.parameters['country']); +// out: 34954 true italy +``` + +Y ahora, todo lo que necesitas hacer es usar Get. oNamed() para navegar por sus rutas nombradas, sin ningún contexto (puede llamar a sus rutas directamente desde su clase BLoC o Controlador), y cuando tu aplicación esté compilada en la web, tus rutas aparecerán en la url < 3 + +### Medios + +Si quieres escuchar Obtener eventos para activar acciones, puedes usar routingCallback a él + +```dart +GetMaterialApp( + routingCallback: (routing) { + if(routing.current == '/second'){ + openAds(); + } + } +) +``` + +Si no está usando GetMaterialApp, puede utilizar la API manual para adjuntar observador de Middleware. + +```dart +void main() { + runApp( + MaterialApp( + onGenerateRoute: Router.generateRoute, + initialRoute: "/", + navigatorKey: Get.key, + navigatorObservers: [ + GetObserver(MiddleWare.observer), // HERE !!! + ], + ), + ); +} +``` + +Crear una clase MiddleWare + +```dart +class MiddleWare { + static observer(Routing routing) { + /// You can listen in addition to the routes, the snackbars, dialogs and bottomsheets on each screen. + ///If you need to enter any of these 3 events directly here, + ///you must specify that the event is != Than you are trying to do. + if (routing.current == '/second' && !routing.isSnackbar) { + Get.snackbar("Hi", "You are on second route"); + } else if (routing.current =='/third'){ + print('last route called'); + } + } +} +``` + +Ahora, usa Get on your code: + +```dart +class First extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + leading: IconButton( + icon: Icon(Icons.add), + onPressed: () { + Get.snackbar("hi", "i am a modern snackbar"); + }, + ), + title: Text('First Route'), + ), + body: Center( + child: ElevatedButton( + child: Text('Open route'), + onPressed: () { + Get.toNamed("/second"); + }, + ), + ), + ); + } +} + +class Second extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + leading: IconButton( + icon: Icon(Icons.add), + onPressed: () { + Get.snackbar("hi", "i am a modern snackbar"); + }, + ), + title: Text('second Route'), + ), + body: Center( + child: ElevatedButton( + child: Text('Open route'), + onPressed: () { + Get.toNamed("/third"); + }, + ), + ), + ); + } +} + +class Third extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text("Third Route"), + ), + body: Center( + child: ElevatedButton( + onPressed: () { + Get.back(); + }, + child: Text('Go back!'), + ), + ), + ); + } +} +``` + +## Navegación sin contexto + +### SnackBars + +Para tener un SnackBar simple con Flutter, debes tener el contexto de Scaffold, o debes usar una GlobalKey conectada a tu Scaffold + +```dart +final snackBar = SnackBar( + content: Text('Hi!'), + action: SnackBarAction( + label: 'I am a old and ugly snackbar :(', + onPressed: (){} + ), +); +// Find the Scaffold in the widget tree and use +// it to show a SnackBar. +Scaffold.of(context).showSnackBar(snackBar); +``` + +Con obtener: + +```dart +Get.snackbar('Hi', 'i am a modern snackbar'); +``` + +Con Get, todo lo que tienes que hacer es llamar a tu Get.snackbar desde cualquier lugar de tu código o personalizarlo como quieras! + +```dart +Get.snackbar( + "Hey i'm a Get SnackBar!", // title + "It's unbelievable! I'm using SnackBar without context, without boilerplate, without Scaffold, it is something truly amazing!", // message + icon: Icon(Icons.alarm), + shouldIconPulse: true, + onTap:(){}, + barBlur: 20, + isDismissible: true, + duration: Duration(seconds: 3), +); + + + ////////// ALL FEATURES ////////// + // Color colorText, + // Duration duration, + // SnackPosition snackPosition, + // Widget titleText, + // Widget messageText, + // bool instantInit, + // Widget icon, + // bool shouldIconPulse, + // double maxWidth, + // EdgeInsets margin, + // EdgeInsets padding, + // double borderRadius, + // Color borderColor, + // double borderWidth, + // Color backgroundColor, + // Color leftBarIndicatorColor, + // List boxShadows, + // Gradient backgroundGradient, + // TextButton mainButton, + // OnTap onTap, + // bool isDismissible, + // bool showProgressIndicator, + // AnimationController progressIndicatorController, + // Color progressIndicatorBackgroundColor, + // Animation progressIndicatorValueColor, + // SnackStyle snackStyle, + // Curve forwardAnimationCurve, + // Curve reverseAnimationCurve, + // Duration animationDuration, + // double barBlur, + // double overlayBlur, + // Color overlayColor, + // Form userInputForm + /////////////////////////////////// +``` + +Si prefieres la tradicional barra de barras o quieres personalizarla desde cero, incluyendo añadir una sola línea (Obtén. nackbar hace uso de un título y mensaje obligatorios), puedes usar +`Get.rawSnackbar();` que proporciona la API RAW en la que se construyó Get.snackbar. + +### Diálogos + +Para abrir el diálogo: + +```dart +Get.dialog(YourDialogWidget()); +``` + +Para abrir el cuadro de diálogo predeterminado: + +```dart +Get.defaultDialog( + onConfirm: () => print("Ok"), + middleText: "Dialog made in 3 lines of code" +); +``` + +También puede utilizar Get.generalDialog en lugar de showGeneralDialog. + +Para todos los demás widgets de diálogo de Flutter, incluyendo cupertinos, puede usar Get.overlayContext en lugar de contexto, y abrirlo en cualquier lugar de su código. +Para los widgets que no usan Overlay, puede usar Get.context. +Estos dos contextos funcionarán en el 99% de los casos para reemplazar el contexto de tu interfaz de usuario excepto los casos en los que herededWidget se utiliza sin un contexto de navegación. + +### Hojas + +Get.bottomSheet es como showModalBottomSheet, pero no necesita contexto. + +```dart +Get.bottomSheet( + Container( + child: Wrap( + children: [ + ListTile( + leading: Icon(Icons.music_note), + title: Text('Music'), + onTap: () {} + ), + ListTile( + leading: Icon(Icons.videocam), + title: Text('Video'), + onTap: () {}, + ), + ], + ), + ) +); +``` + +## Navegación anidada + +Haz que la navegación anidada de Flutter sea aún más fácil. +No necesita el contexto, y encontrará su pila de navegación por Id. + +- NOTA: Crear pilas de navegación paralelas puede ser peligroso. Lo ideal es no utilizar NestedNavigators ni utilizar esparcidamente. Si su proyecto lo necesita, siga adelante, pero ten en cuenta que mantener múltiples pilas de navegación en memoria puede no ser una buena idea para el consumo de RAM. + +Mira lo simple que es: + +```dart +Navigator( + key: Get.nestedKey(1), // create a key by index + initialRoute: '/', + onGenerateRoute: (settings) { + if (settings.name == '/') { + return GetPageRoute( + page: () => Scaffold( + appBar: AppBar( + title: Text("Main"), + ), + body: Center( + child: TextButton( + color: Colors.blue, + onPressed: () { + Get.toNamed('/second', id:1); // navigate by your nested route by index + }, + child: Text("Go to second"), + ), + ), + ), + ); + } else if (settings.name == '/second') { + return GetPageRoute( + page: () => Center( + child: Scaffold( + appBar: AppBar( + title: Text("Main"), + ), + body: Center( + child: Text("second") + ), + ), + ), + ); + } + } +), +``` diff --git a/docs/i18n/es/docusaurus-plugin-content-docs/current/pillars/state-management.md b/docs/i18n/es/docusaurus-plugin-content-docs/current/pillars/state-management.md new file mode 100644 index 000000000..13987b52e --- /dev/null +++ b/docs/i18n/es/docusaurus-plugin-content-docs/current/pillars/state-management.md @@ -0,0 +1,768 @@ +--- +sidebar_position: 1 +--- + +# Estado + +GetX no usa Streams o ChangeNotifier como otros administradores de estado. ¿Por qué? Además de crear aplicaciones para android, iOS, web, ventanas, macos y linux, con GetX puede construir aplicaciones de servidor con la misma sintaxis que Flutter/GetX. Para mejorar el tiempo de respuesta y reducir el consumo de RAM, creamos GetValue y GetStream, que son soluciones de baja latencia que ofrecen un gran rendimiento, a un bajo costo operativo. Utilizamos esta base para construir todos nuestros recursos, incluida la gestión estatal. + +- _Complexity_: Algunos administradores estatales son complejos y tienen un montón de boilerplate. Con GetX no tienes que definir una clase para cada evento, el código es muy limpio y claro, y usted hace mucho más escribiendo menos. Muchas personas han renunciado a Flutter por este tema y ahora finalmente tienen una solución absurdamente sencilla para la gestión de los Estados. +- _Sin generadores de código_: Pasa la mitad de su tiempo de desarrollo escribiendo la lógica de su aplicación. Algunos administradores de estado confían en que los generadores de código tengan código mínimamente legible. Cambiar una variable y tener que ejecutar build\_runner puede ser improductivo, y a menudo el tiempo de espera después de un polvo limpio será largo, y usted tendrá que beber un montón de café. + +Con GetX todo es reactivo, y nada depende de generadores de código, aumentando su productividad en todos los aspectos de su desarrollo. + +- _No depende del contexto_: Probablemente ya necesites enviar el contexto de tu vista a un controlador, hacer que la vista se acople a su lógica de negocio alto. Probablemente haya tenido que usar una dependencia para un lugar que no tiene contexto, y tuvo que pasar el contexto a través de varias clases y funciones. Esto no existe con GetX. Usted tiene acceso a sus controladores desde dentro de sus controladores sin ningún contexto. No necesita enviar el contexto por parámetro para literalmente nada. +- _Control granular_: la mayoría de los administradores de estados se basan en ChangeNotifier. CambiarNotificador notificará todos los widgets que dependen de ellos cuando se llama a notificarListeners. Si tienes 40 widgets en una pantalla, que tienen una variable de tu clase ChangeNotificfier al actualizar uno, todos ellos serán reconstruidos. + +Con GetX, incluso los widgets anidados son respetados. Si tienes Obx viendo tu vista de lista, y otra viendo una casilla dentro de la vista de lista, al cambiar el valor de la casilla de verificación, sólo se actualizará cuando se cambie el valor de la lista, sólo se actualizará la vista de lista. + +- _Sólo reconstruye si su variable cambia REGISTRAMENTE_: GetX tiene control de flujo, lo que significa que si muestra un texto con 'Paola', si cambia la variable observable a 'Paola' de nuevo, el widget no será reconstruido. Esto se debe a que GetX sabe que 'Paola' ya se muestra en Texto, y no hará reconstrucciones innecesarias. + +La mayoría (si no todos) los administradores de estado actuales se reconstruirán en la pantalla. + +## Gestor de estado reactivo + +La programación reactiva puede alienar a mucha gente porque se dice que es complicada. GetX convierte la programación reactiva en algo bastante simple: + +- No necesitará crear StreamControllers. +- No necesitará crear un StreamBuilder para cada variable +- No necesitará crear una clase para cada estado. +- No necesitará crear un get para un valor inicial. + +Programación reactiva con Get es tan fácil como usar setState. + +Imaginemos que tienes una variable de nombre y queremos que cada vez que la cambies, todos los widgets que la usan se cambien automáticamente. + +Esta es tu variable de contador: + +```dart +var name = 'Jonatas Borges'; +``` + +Para hacerla observable, sólo tienes que añadir ".obs" al final de la misma: + +```dart +var name = 'Jonatas Borges'.obs; +``` + +Eso es todo. Es _es_ simple. + +A partir de ahora, podríamos referirnos a esta variable reactiva-".obs"(ervables) como _Rx_. + +¿Qué hicimos bajo el capó? Hemos creado un `Stream` de `String` s, asignado el valor inicial `"Jonatas Borges"` , notificamos a todos los widgets que usan `"Jonatas Borges"` que ahora "pertenecen" a esta variable, y cuando el valor _Rx_ cambie, también tendrán que cambiar. + +Esta es la **magia de GetX**, gracias a las capacidades de Dart. + +Pero, como sabemos, un `Widget` sólo puede ser cambiado si está dentro de una función, porque las clases estáticas no tienen el poder de "cambio automático". + +Necesitarás crear un `StreamBuilder` , suscribirte a esta variable para escuchar los cambios, y crea una "cascada" de `StreamBuilder` anidado si quieres cambiar varias variables en el mismo ámbito, ¿verdad? + +No, no necesitas un `StreamBuilder` , pero tienes razón sobre las clases estáticas. + +Bueno, en la vista, normalmente tenemos un montón de boilerplate cuando queremos cambiar un Widget específico, esa es la manera de Flutter. +Con **GetX** también puedes olvidarte de este código de boilerplate . + +`StreamBuilder( … )` ? `initialValue: …` ? `builder: …` ? No, sólo necesitas colocar esta variable dentro de un Widget `Obx()`. + +```dart +Obx (() => Text (controller.name)); +``` + +_¿Qué necesitas memorizar?_ Sólo `Obx(() =>` . + +Usted está pasando ese Widget a través de una función de flecha en un `Obx()` (el "Observador" del _Rx_). + +`Obx` es bastante inteligente, y solo cambiará si el valor de `controller.name` cambia. + +Si `name` es `"John"` , y lo cambias a `"John"` ( `name. alue = "John"` ), como es el mismo `valor` que antes, nada cambiará en la pantalla, y `Obx` , para ahorrar recursos, simplemente ignorará el nuevo valor y no reconstruirá el Widget. **¿No es asombroso?** + +> Entonces, ¿qué pasa si tengo 5 variables _Rx_ (observables) dentro de un `Obx`? + +Sólo se actualizará cuando **cualquiera** de ellos cambie. + +> Y si tengo 30 variables en una clase, cuando actualicé una, ¿actualizará **todas** las variables que están en esa clase? + +No, sólo el **Widget específico** que usa esa variable _Rx_. + +Por lo tanto, **GetX** sólo actualiza la pantalla, cuando la variable _Rx_ cambia su valor. + +``` + +final isOpen = false.obs; + +// NOTHING will happen... same value. +void onButtonTap() => isOpen.value=false; +``` + +### Ventajas + +**GetX()** te ayuda cuando necesitas un control **granular** sobre lo que se está actualizando. + +Si no necesitas `identificadores únicos` , porque todas tus variables serán modificadas cuando realices una acción, entonces usa `GetBuilder` , +porque es un Actualizador de Estado Simple (en bloques, como `setState()` ), hecho en unas pocas líneas de código. +Se hizo simple, para tener el menor impacto de la CPU, y sólo para cumplir un único propósito (una reconstrucción de _Estado_) y gastar los recursos mínimos posibles. + +Si necesitas un administrador de estado **poderoso**, no puedes ir mal con **GetX**. + +No funciona con variables, pero **flows**, todo en él es `Streams` bajo el capó. + +Puedes usar _rxDart_ junto con él, porque todo es `Streams`, +puedes escuchar el `evento` de cada variable "_Rx_", +porque todo en él son `Streams`. + +Es literalmente un enfoque _BLoC_ más fácil que _MobX_, y sin generadores de código ni decoraciones. +Puedes convertir **cualquier cosa** en un _"Observable"_ con sólo un `.obs` . + +### Máximo rendimiento: + +Además de tener un algoritmo inteligente para recompilaciones mínimas, **GetX** utiliza comparadores +para asegurarse de que el Estado ha cambiado. + +If you experience any errors in your app, and send a duplicate change of State, +**GetX** will ensure it will not crash. + +Con **GetX** el estado sólo cambia si el `valor` cambia. +Esa es la diferencia principal entre **GetX**, y usando \_ `computed` de MobX\_. +Al unirse a dos **observables**, y uno cambia; el oyente de ese _observable_ también cambiará. + +Con **GetX**, si te unes a dos variables, `GetX()` (similar a `Observer()` ) sólo se reconstruirá si implica un cambio real de Estado. + +### Declarando una variable reactiva + +Tienes 3 maneras de convertir una variable en un "observable". + +1 - El primero está usando **`Rx{Type}`**. + +```dart +// initial value is recommended, but not mandatory +final name = RxString(''); +final isLogged = RxBool(false); +final count = RxInt(0); +final balance = RxDouble(0.0); +final items = RxList([]); +final myMap = RxMap({}); +``` + +2 - El segundo es usar **`Rx`** y usar Darts Genéricos, `Rx` + +```dart +final name = Rx(''); +final isLogged = Rx(false); +final count = Rx(0); +final balance = Rx(0.0); +final number = Rx(0); +final items = Rx>([]); +final myMap = Rx>({}); + +// Custom classes - it can be any class, literally +final user = Rx(); +``` + +3 - El tercero, más práctico, más fácil y preferido enfoque, sólo añade **`.obs`** como una propiedad de tu `valor`: + +```dart +final name = ''.obs; +final isLogged = false.obs; +final count = 0.obs; +final balance = 0.0.obs; +final number = 0.obs; +final items = [].obs; +final myMap = {}.obs; + +// Custom classes - it can be any class, literally +final user = User().obs; +``` + +##### Tener un estado reactivo es fácil. + +Como sabemos, _Dart_ ahora se dirige hacia _null\_nul_. +Para estar preparado, a partir de ahora, siempre deberías iniciar tus variables _Rx_ con un **valor inicial**. + +> Transformar una variable en un _observable_ + _valor inicial_ con **GetX** es el enfoque más simple y práctico. + +Literalmente añadirás un " `.obs` " al final de tu variable, y **eso**, lo has hecho observable, +y su `. alue` , bueno, será el _valor inicial_). + +### Usar los valores en la vista + +```dart +// controller file +final count1 = 0.obs; +final count2 = 0.obs; +int get sum => count1.value + count2.value; +``` + +```dart +// view file +GetX( + builder: (controller) { + print("count 1 rebuild"); + return Text('${controller.count1.value}'); + }, +), +GetX( + builder: (controller) { + print("count 2 rebuild"); + return Text('${controller.count2.value}'); + }, +), +GetX( + builder: (controller) { + print("count 3 rebuild"); + return Text('${controller.sum}'); + }, +), +``` + +Si incrementamos `count1.value++` , se imprimirá: + +- `cuenta 1 reconstrucción` + +- `cuenta 3 de reconstrucción` + +porque `count1` tiene un valor de `1` y `1 + 0 = 1` , cambiando el valor de `suma` getter. + +Si cambiamos `count2.value++` , se imprimirá: + +- `count 2 recompilación` + +- `cuenta 3 de reconstrucción` + +porque `count2.value` cambió, y el resultado de la `sum` es ahora `2` . + +- NOTA: De forma predeterminada, el primer evento reconstruirá el widget, incluso si es el mismo `value`. + +Este comportamiento existe debido a variables booleanas. + +Imagina que hiciste esto: + +```dart +var isLogged = false.obs; +``` + +Y luego, comprobaste si un usuario está "conectado" para activar un evento en `ever` . + +```dart +@override +onInit() async { + ever(isLogged, fireRoute); + isLogged.value = await Preferences.hasToken(); +} + +fireRoute(logged) { + if (logged) { + Get.off(Home()); + } else { + Get.off(Login()); + } +} +``` + +si `hasToken` fuera `false` , no habría ningún cambio en `isLogged` , así que `ever()` nunca sería llamado. +Para evitar este tipo de comportamiento, el primer cambio a un _observable_ siempre activará un evento, +incluso si contiene el mismo `. alue` . + +Puede eliminar este comportamiento si lo desea, usando: +`isLogged.firstRebuild = false;` + +### Condiciones para reconstruir + +Además, Get proporciona un control refinado del estado. Puede condicionar un evento (como agregar un objeto a una lista), en una determinada condición. + +```dart +// First parameter: condition, must return true or false. +// Second parameter: the new value to apply if the condition is true. +list.addIf(item < limit, item); +``` + +Sin decoraciones, sin un generador de código, sin complicaciones :smile: + +¿Conoces la aplicación contador de Flutter? Tu clase Controller podría verse así: + +```dart +class CountController extends GetxController { + final count = 0.obs; +} +``` + +Con un simple: + +```dart +controller.count.value++ +``` + +Puede actualizar la variable contador en su interfaz de usuario, independientemente de dónde se almacena. + +### Donde .obs pueden ser usados + +Puedes transformar cualquier cosa en obs. Aquí hay dos maneras de hacerlo: + +- Puedes convertir los valores de tu clase a obs + +```dart +class RxUser { + final name = "Camila".obs; + final age = 18.obs; +} +``` + +- o puede convertir toda la clase para ser observable + +```dart +class User { + User({String name, int age}); + var name; + var age; +} + +// when instantianting: +final user = User(name: "Camila", age: 18).obs; +``` + +### Nota sobre listas + +Las listas son completamente observables al igual que los objetos dentro de ellas. De esta manera, si añade un valor a una lista, automáticamente reconstruirá los widgets que la utilizan. + +También no necesitas usar ".value" con listas, la increíble api dart nos permitió eliminar eso. +Lamentablemente no se pueden extender tipos primitivos como String y int, haciendo uso de . alue obligory, pero eso no será un problema si trabajas con consigue y setters para estos. + +```dart +// On the controller +final String title = 'User Info:'.obs +final list = List().obs; + +// on the view +Text(controller.title.value), // String need to have .value in front of it +ListView.builder ( + itemCount: controller.list.length // lists don't need it +) +``` + +Cuando estás haciendo que tus propias clases sean observables, hay una forma diferente de actualizarlas: + +```dart +// on the model file +// we are going to make the entire class observable instead of each attribute +class User() { + User({this.name = '', this.age = 0}); + String name; + int age; +} + +// on the controller file +final user = User().obs; +// when you need to update the user variable: +user.update( (user) { // this parameter is the class itself that you want to update +user.name = 'Jonny'; +user.age = 18; +}); +// an alternative way of update the user variable: +user(User(name: 'João', age: 35)); + +// on view: +Obx(()=> Text("Name ${user.value.name}: Age: ${user.value.age}")) +// you can also access the model values without the .value: +user().name; // notice that is the user variable, not the class (variable has lowercase u) +``` + +No tienes que trabajar con conjuntos si no lo deseas. Puedes usar el "assign 'and" asignado "api". +La api "asignar" borrará su lista y añadirá un solo objeto que desea comenzar allí. +La api "assignAll" borrará la lista existente y añadirá cualquier objeto iterable que se inyecte en ella. + +### ¿Por qué tengo que usar .value + +Podríamos eliminar la obligación de usar 'valor' en 'cadena' e 'int' con un generador de código y decoración simple, pero el propósito de esta biblioteca es precisamente evitar dependencias externas. Queremos ofrecer un entorno listo para la programación, que implique lo esencial (gestión de rutas, dependencias y estados), de una manera sencilla, ligera y eficiente, sin necesidad de un paquete externo. + +Literalmente puedes añadir 3 letras a tu pubspec (get) y dos puntos y empezar a programar. Todas las soluciones incluidas por defecto, desde la gestión de rutas hasta la gestión estatal, apuntan a la facilidad, productividad y rendimiento. + +El peso total de esta biblioteca es menor que el de un único administrador estatal, aunque sea una solución completa, y eso es lo que ustedes deben entender. + +Si usted está molesto por `. alue` , y como un generador de código, MobX es una gran alternativa, y puede usarlo junto con Get. Para aquellos que quieran añadir una sola dependencia en pubspec y empezar a programar sin preocuparse por que la versión de un paquete sea incompatible con otra, o si el error de una actualización de estado proviene del administrador de estado o dependencia, o aún así, no quieren preocuparse por la disponibilidad de controladores, si literalmente "sólo programación", obtener es perfecto. + +Si no tiene ningún problema con el generador de código MobX, o no tiene ningún problema con el boilerplate BLoC, usted puede simplemente usar Get para rutas, y olvidar que tiene el administrador del estado. Obtener SEM y RSM nacieron de la necesidad, mi empresa tenía un proyecto con más de 90 controladores, y el generador de código simplemente tardó más de 30 minutos en completar sus tareas después de una limpieza de flujido en una máquina razonablemente buena, si su proyecto tiene 5, 10, 15 controladores, cualquier administrador estatal le suministrará bien. Si tiene un proyecto absurdamente grande, y el generador de código es un problema para usted, se le ha concedido esta solución. + +Obviamente, si alguien quiere contribuir al proyecto y crear un generador de código, o algo similar, enlazaré en este léame como una alternativa, Mi necesidad no es la necesidad de todos los desarrolladores, pero por ahora digo, hay buenas soluciones que ya hacen eso, como MobX. + +### Obx() + +Escribir en Get using Bindings es innecesario. puede utilizar el widget Obx en lugar de GetX que sólo recibe la función anónima que crea un widget. +Obviamente, si no usas un tipo, necesitarás tener una instancia de tu controlador para usar las variables, o usar `Get. enlazar()` .value o Controller.to.value para recuperar el valor. + +### Trabajadores + +Los trabajadores le ayudarán, activando llamadas específicas cuando ocurra un evento. + +```dart +/// Called every time `count1` changes. +ever(count1, (_) => print("$_ has been changed")); + +/// Called only first time the variable $_ is changed +once(count1, (_) => print("$_ was changed once")); + +/// Anti DDos - Called every time the user stops typing for 1 second, for example. +debounce(count1, (_) => print("debouce$_"), time: Duration(seconds: 1)); + +/// Ignore all changes within 1 second. +interval(count1, (_) => print("interval $_"), time: Duration(seconds: 1)); +``` + +Todos los trabajadores (excepto `debounce` ) tienen un parámetro llamado `condition`, que puede ser un `bool` o un callback que devuelva un `bool` . +Esta `condición` define cuando la función `callback` se ejecuta. + +Todos los trabajadores devuelven una instancia de `Worker`, que puedes usar para cancelar ( a través de `dispose()` ) el worker. + +- **`nunca`** + +se llama cada vez que la variable _Rx_ emite un nuevo valor. + +- **`todo`** + +Al igual que `ever` , pero toma una `List` de valores _Rx_ llamada cada vez que su variable es cambiada. Eso es todo. + +- **`una vez`** + +'una vez' se llama sólo la primera vez que la variable ha sido cambiada. + +- **`debounce`** + +'debounce' es muy útil en las funciones de búsqueda, donde sólo quieres que se llame a la API cuando el usuario termine de teclear. Si el usuario escribe "Jonny", tendrá 5 búsquedas en las APIs, por la letra J, n, n y y. Con Get esto no sucede, porque usted tendrá un Trabajador de "deshacer" que sólo se activará al final de la escritura. + +- **`intervalo`** + +'intervalo' es diferente del escombro. debouce si el usuario hace 1000 cambios a una variable dentro de 1 segundo, enviará sólo el último después del temporizador sofocado (el valor por defecto es 800 milisegundos). Intervalo en su lugar ignorará todas las acciones del usuario durante el período asfixiado. Si envías eventos por 1 minuto, 1000 por segundo, descomprimir sólo te enviará el último, cuando el usuario deje de abrir eventos. el intervalo entregará eventos cada segundo, y si se establece en 3 segundos, producirá 20 eventos ese minuto. Esto se recomienda para evitar abusos, en funciones donde el usuario puede hacer clic rápidamente en algo y obtener alguna ventaja (imagina que el usuario puede ganar monedas haciendo clic en algo, si hizo clic 300 veces en el mismo minuto, tendría 300 monedas, usando intervalo, puedes establecer un marco de tiempo durante 3 segundos, e incluso luego hacer clic en 300 o mil veces, el máximo que obtendría en 1 minuto serían 20 monedas, haciendo clic en 300 o 1 millón de veces). La desconexión es adecuada para anti-DDos, para funciones como buscar donde cada cambio a onChange causaría una consulta a tu api. Debounce esperará a que el usuario deje de escribir el nombre, para hacer la solicitud. Si se utilizara en el escenario de monedas mencionado anteriormente, el usuario sólo ganaría 1 moneda, porque sólo se ejecuta cuando el usuario "pausa" para el tiempo establecido. + +- NOTA: Los trabajadores deben ser usados siempre al iniciar un controlador o clase, por lo que siempre debe estar en onInit (recomendado), constructor de clase, o el estado inicial de un StatefulWidget (esta práctica no se recomienda en la mayoría de los casos, pero no debería tener efectos secundarios). + +## Gestor de Estado simple + +Obtener tiene un administrador de estado que es extremadamente ligero y fácil, que no utiliza ChangeNotifier, satisfará especialmente las necesidades de los nuevos a Flutter, y no causará problemas para grandes aplicaciones. + +GetBuilder está dirigido precisamente al control de múltiples estados. Imagínese que ha añadido 30 productos a un carrito, haga clic en eliminar uno, al mismo tiempo que la lista se actualiza, el precio se actualiza y la insignia en el carrito de la compra se actualiza a un número más pequeño. Este tipo de enfoque hace que GetBuilder mate, porque agrupa a todos y los cambia a la vez sin ninguna "lógica computacional" para eso. GetBuilder fue creado con este tipo de situación en mente, desde el cambio efemeral de estado, puede usar setState y no necesitará un gestor de estado para esto. + +De esta manera, si quieres un controlador individual, puedes asignar IDs para eso, o usar GetX. Esto depende de ti, recordando que cuanto más widgets "individual" tengas, más destacará el rendimiento de GetX mientras que el rendimiento de GetBuilder debe ser superior, cuando hay un cambio de estado múltiple. + +### Ventajas + +1. Actualizar sólo los widgets necesarios. + +2. No utiliza changeNotifier, es el gestor de estado el que usa menos memoria (cerca de 0mb). + +3. ¡Olvidar StatefulWidget! Con Get nunca lo necesitará. Con los otros administradores de estado, probablemente tendrás que usar StatefulWidget para obtener la instancia de tu Provider, BLoC, Controlador MobX, etc. Pero, ¿alguna vez has parado a pensar que tu appBar, tu andamio y la mayoría de los widgets que están en tu clase son sin estado? Entonces, ¿por qué salvar el estado de toda una clase, si sólo puedes salvar el estado del Widget que es estatuario? Consigue que esto también se resuelva. Crea una clase sin Estado, haz que todo esté sin estado. Si necesita actualizar un solo componente, envolverlo con GetBuilder, y su estado se mantendrá. + +4. Organiza tu proyecto de forma real! Los controladores no deben estar en tu interfaz de usuario, colocar tu TextEditController, o cualquier controlador que utilices dentro de tu clase Controller. + +5. ¿Necesitas activar un evento para actualizar un widget tan pronto como se procese? GetBuilder tiene la propiedad "initState", al igual que StatefulWidget, y puedes llamar a eventos desde tu controlador, directamente desde él, ya no más eventos colocados en tu estado inicial. + +6. ¿Necesitas desencadenar una acción como cerrar secuencias, temporizadores y etc? GetBuilder también tiene la propiedad de disponer, donde puede llamar a eventos tan pronto como ese widget sea destruido. + +7. Usar streams sólo si es necesario. Puede utilizar sus Controladores StreamControllers dentro de su controlador normalmente, y usar StreamBuilder también normalmente, pero recuerde, un flujo consume razonablemente memoria, la programación reactiva es hermosa, pero no debería abusar de ella. 30 streams abiertos simultáneamente pueden ser peores que changeNotifier (y changeNotifier es muy mal). + +8. Actualizar widgets sin gastar rama para eso. Obtén tiendas sólo el ID del creador GetBuilder, y actualiza ese GetBuilder cuando sea necesario. El consumo de memoria del almacenamiento con ID en memoria es muy bajo, incluso para miles de GetBuilders. Cuando creas un nuevo GetBuilder, realmente estás compartiendo el estado de GetBuilder que tiene un ID de creador. Un nuevo estado no se crea para cada GetBuilder, que guarda un LOT OF ram para aplicaciones grandes. Básicamente su solicitud será completamente sin estado y los pocos Widgets que serán Stateful (dentro de GetBuilder) tendrán un solo estado, y por lo tanto actualizar uno los actualizará todos. El Estado es sólo uno. + +9. Get es omnisciente y en la mayoría de los casos sabe exactamente el tiempo para sacar a un controlador de la memoria. No deberías preocuparte por cuándo desmontar un controlador, Obtener sabe el mejor momento para hacer esto. + +### Uso + +```dart +// Create controller class and extends GetxController +class Controller extends GetxController { + int counter = 0; + void increment() { + counter++; + update(); // use update() to update counter variable on UI when increment be called + } +} +// On your Stateless/Stateful class, use GetBuilder to update Text when increment be called +GetBuilder( + init: Controller(), // INIT IT ONLY THE FIRST TIME + builder: (_) => Text( + '${_.counter}', + ), +) +//Initialize your controller only the first time. The second time you are using ReBuilder for the same controller, do not use it again. Your controller will be automatically removed from memory as soon as the widget that marked it as 'init' is deployed. You don't have to worry about that, Get will do it automatically, just make sure you don't start the same controller twice. +``` + +**Hecho!** + +- Ya has aprendido a manejar estados con Get. + +- Nota: Es posible que desee una organización más grande, y no utilizar la propiedad init. Para eso, puedes crear una clase y extender la clase Binding y dentro de ella mencionar los controladores que se crearán dentro de esa ruta. No se crearán controladores en ese momento, al contrario, se trata simplemente de una declaración. para que la primera vez que utilices un Controller, Obtener sabrá dónde mirar. Get will remain perazyLoad, and will continue to dispose Controllers when they are not needed. Vea el ejemplo pub.dev para ver cómo funciona. + +Si navega muchas rutas y necesita datos que estaban en su controlador previamente usado, sólo necesita usar GetBuilder otra vez (sin inicio): + +```dart +class OtherClass extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + body: Center( + child: GetBuilder( + builder: (s) => Text('${s.counter}'), + ), + ), + ); + } + +``` + +Si necesitas usar tu controlador en muchos otros lugares, y fuera de GetBuilder, sólo tienes que crear un get en tu controlador y tenerlo fácilmente. (o usa `Get.find()` ) + +```dart +class Controller extends GetxController { + + /// You do not need that. I recommend using it just for ease of syntax. + /// with static method: Controller.to.increment(); + /// with no static method: Get.find().increment(); + /// There is no difference in performance, nor any side effect of using either syntax. Only one does not need the type, and the other the IDE will autocomplete it. + static Controller get to => Get.find(); // add this line + + int counter = 0; + void increment() { + counter++; + update(); + } +} +``` + +Y entonces puedes acceder directamente a tu controlador, de esa manera: + +```dart +FloatingActionButton( + onPressed: () { + Controller.to.increment(), + } // This is incredibly simple! + child: Text("${Controller.to.counter}"), +), +``` + +Al pulsar FloatingActionButton, todos los widgets que estén escuchando la variable 'contador' se actualizarán automáticamente. + +### Cómo maneja los controladores + +Digamos lo siguiente: + +`Clase a => Clase B (tiene controlador X) => Clase C (tiene controlador X)` + +En la clase A, el controlador no está todavía en la memoria, porque aún no la ha utilizado (Get is lazyLoad). En la clase B usó el controlador, y entró en la memoria. En la clase C utilizaste el mismo controlador que en la clase B, Obtener compartirá el estado del controlador B con el controlador C, y el mismo controlador todavía está en memoria. Si cierra la pantalla C y la pantalla B, Get sacará automáticamente el controlador X de la memoria y liberará recursos porque la clase a no está usando el controlador. Si navega a B de nuevo, el controlador X volverá a entrar en la memoria, si en lugar de ir a la clase C, volviendo a la clase A otra vez, Get sacará el controlador de la memoria de la misma manera. Si la clase C no usó el controlador, y sacaste la clase B de la memoria, ninguna clase usaría el controlador X y tampoco estaría dispuesta. La única excepción que puede molestar con Get, es si elimina B de la ruta inesperadamente, e intenta usar el controlador en C. En este caso, el ID del creador del controlador que estaba en B fue eliminado, y Get fue programado para eliminarlo de la memoria de cada controlador que no tiene ID de creador. Si usted tiene la intención de hacer esto, agregue la bandera "autoRemove: false" a la clase B GetBuilder y use adoptID = true; en la clase C GetBuilder. + +### Ya no necesitarás StatefulWidgets + +Usar StatefulWidgets significa almacenar el estado de pantallas enteras innecesariamente, incluso porque necesita reconstruir mínimamente un widget, lo insertarás en un Consumer/Observer/BlocProvider/GetBuilder/GetX/Obx, el cual será otro StatefulWidget. +La clase StatefulWidget es una clase mayor que StatelessWidget, que asignará más RAM, y esto puede no marcar una diferencia significativa entre una o dos clases, pero sin duda lo hará cuando tenga 100 de ellas! +A menos que necesite usar una mixin, como TickerProviderStateMixin, será totalmente innecesario usar un StatefulWidget con Get. + +Puedes llamar a todos los métodos de un StatefulWidget directamente desde un GetBuilder. +Si necesita llamar al método initState() o dispose() por ejemplo, puede llamarlos directamente; + +```dart +GetBuilder( + initState: (_) => Controller.to.fetchApi(), + dispose: (_) => Controller.to.closeStreams(), + builder: (s) => Text('${s.username}'), +), +``` + +Un enfoque mucho mejor que esto es usar el método onInit() y onClose() directamente desde el controlador. + +```dart +@override +void onInit() { + fetchApi(); + super.onInit(); +} +``` + +- NOTA: Si quieres iniciar un método por el momento el controlador es llamado por primera vez, NO ES NECESARIO usar constructores para esto, de hecho, usando un paquete orientado al rendimiento como Get, esto limita con la mala práctica. porque se desvia de la lógica en la que se crean o asignan los controladores (si se crea una instancia de este controlador, el constructor será llamado inmediatamente, estarás poblando un controlador antes de que se utilice, está asignando memoria sin que esté en uso, esto definitivamente perjudica los principios de esta biblioteca). Los métodos onInit(); y onClose(); fueron creados para esto, serán llamados cuando el controlador sea creado, o usado por primera vez, dependiendo de si usted está usando Get. azyPut o no. Si quieres, por ejemplo, hacer una llamada a tu API para rellenar datos, puedes olvidarte del método anticuado de initState/dispose, simplemente inicia tu llamada a la api en onInit, y si necesitas ejecutar cualquier comando como cerrar streams, usa onClose() para eso. + +### Por qué existe + +El propósito de este paquete es precisamente ofrecerle una solución completa para la navegación de rutas, gestión de dependencias y estados, utilizando las menos dependencias posibles, con un alto grado de desacoplamiento. Consiga involucrarse con todas las APIs de nivel alto y bajo dentro de sí mismo, para asegurarse de que trabaja con el menor acoplamiento posible. Centralizamos todo en un solo paquete, para asegurar que no tenga ningún tipo de acoplamiento en su proyecto. De esa manera, solo puedes poner widgets en tu vista, y dejar libre la parte de tu equipo que trabaja con la lógica de negocio. trabajar con la lógica de negocio sin depender de ningún elemento de la Vista. Esto proporciona un entorno de trabajo mucho más limpio, de modo que parte de tu equipo sólo funciona con widgets, sin preocuparse por enviar datos a tu controlador, y parte de su equipo trabaja sólo con la lógica de negocio en su pan, sin depender de ningún elemento de la vista. + +Así que para simplificar esto: +No necesitas llamar a métodos en initState y enviarlos por parámetro a tu controlador, ni utilice el constructor de su controlador para eso, tiene el método onInit() que se llama en el momento adecuado para iniciar sus servicios. +No necesita llamar al dispositivo, tiene el método onClose() que será llamado en el momento exacto en que su controlador ya no es necesario y será eliminado de la memoria. De esa manera, deje las vistas para los widgets solamente, acepte cualquier tipo de lógica de negocio de ella. + +No llamar a un método de dispose dentro de GetxController, no hará nada, recuerda que el controlador no es un Widget, no debería "eliminarlo", y será eliminada de forma automática e inteligente de la memoria por Get. Si ha utilizado alguna secuencia en ella y quiere cerrarla, simplemente insertarla en el método de cierre. Ejemplo: + +```dart +class Controller extends GetxController { + StreamController user = StreamController(); + StreamController name = StreamController(); + + /// close stream = onClose method, not dispose. + @override + void onClose() { + user.close(); + name.close(); + super.onClose(); + } +} +``` + +Ciclo de vida del controlador: + +- onInit() donde se crea. +- onClose() donde está cerrado para realizar cualquier cambio en la preparación del método de eliminación +- eliminado: no tiene acceso a esta API porque está literalmente eliminando el controlador de la memoria. Es literalmente eliminado, sin dejar rastro. + +### Otras formas de usarlo + +Puede utilizar la instancia del controlador directamente en el valor de GetBuilder: + +```dart +GetBuilder( + init: Controller(), + builder: (value) => Text( + '${value.counter}', //here + ), +), +``` + +También puede que necesites una instancia de tu controlador fuera de tu GetBuilder, y puedes usar estos métodos para lograr esto: + +```dart +class Controller extends GetxController { + static Controller get to => Get.find(); +[...] +} +// on you view: +GetBuilder( + init: Controller(), // use it only first time on each controller + builder: (_) => Text( + '${Controller.to.counter}', //here + ) +), +``` + +o + +```dart +class Controller extends GetxController { + // static Controller get to => Get.find(); // with no static get +[...] +} +// on stateful/stateless class +GetBuilder( + init: Controller(), // use it only first time on each controller + builder: (_) => Text( + '${Get.find().counter}', //here + ), +), +``` + +- Puedes usar enfoques "no canónicos" para hacer esto. Si estás usando algún otro gestor de dependencias, como get\_it, modular, etc., y solo quieres entregar la instancia del controlador, puedes hacer esto: + +```dart +Controller controller = Controller(); +[...] +GetBuilder( + init: controller, //here + builder: (_) => Text( + '${controller.counter}', // here + ), +), + +``` + +### IDs únicos + +Si desea refinar el control de actualizaciones de un widget con GetBuilder, puede asignarles IDs únicos: + +```dart +GetBuilder( + id: 'text' + init: Controller(), // use it only first time on each controller + builder: (_) => Text( + '${Get.find().counter}', //here + ), +), +``` + +Y actualícela este formulario: + +```dart +update(['text']); +``` + +También puede imponer condiciones para la actualización: + +```dart +update(['text'], counter < 10); +``` + +GetX hace esto automáticamente y sólo reconstruye el widget que utiliza la variable exacta que fue cambiada, si cambia una variable a la misma que la anterior y eso no implica un cambio de estado , GetX no reconstruirá el widget para ahorrar memoria y ciclos de CPU (3 se muestra en la pantalla, y cambias la variable a 3 de nuevo. En la mayoría de los administradores estatales, esto causará una nueva reconstrucción, pero con GetX el widget sólo se reconstruirá de nuevo, si de hecho su estado ha cambiado). + +## Mezclar los dos administradores estatales + +Algunas personas abrieron una petición de características, ya que querían usar solo un tipo de variable reactiva, y las otras mecánicas, y necesarias para insertar un Obx en un GetBuilder para esto. Pensando en ello se creó MixinBuilder. Permite tanto cambios reactivos cambiando variables ".obs", como actualizaciones mecánicas a través de update(). Sin embargo, de los 4 widgets él es el que consume más recursos, ya que además de tener una Suscripción para recibir eventos de cambio de sus hijos, se suscribe al método de actualización de su controlador. + +Extender GetxController es importante, ya que tienen ciclos de vida, y pueden "iniciar" y "terminar" eventos en sus métodos onInit() y onClose(). Puede usar cualquier clase para esto, pero le recomiendo encarecidamente que utilice la clase GetxController para colocar sus variables, sean observables o no. + +## Mixin de estado + +Otra forma de manejar tu estado `UI` es usar el `StateMixin` . +Para implementarlo, usa el `con` para agregar el `StateMixin` +a tu controlador que permite un modelo T. + +```dart +class Controller extends GetController with StateMixin{} +``` + +El método `change()` cambia el Estado siempre que queremos. +Simplemente pase los datos y el estado de esta manera: + +```dart +change(data, status: RxStatus.success()); +``` + +RxStatus permite estos estados: + +```dart +RxStatus.loading(); +RxStatus.success(); +RxStatus.empty(); +RxStatus.error('message'); +``` + +Para representarlo en la interfaz de usuario, use: + +```dart +class OtherClass extends GetView { + @override + Widget build(BuildContext context) { + return Scaffold( + + body: controller.obx( + (state)=>Text(state.name), + + // here you can put your custom loading indicator, but + // by default would be Center(child:CircularProgressIndicator()) + onLoading: CustomLoadingIndicator(), + onEmpty: Text('No data found'), + + // here also you can set your own error widget, but by + // default will be an Center(child:Text(error)) + onError: (error)=>Text(error), + ), + ); +} +``` + +## GetBuilder vs GetX vs Obx vs MixinBuilder + +En una década trabajando con la programación pude aprender algunas lecciones valiosas. + +Mi primer contacto con la programación reactiva fue tan "wow, esto es increíble" y de hecho la programación reactiva es increíble. +Sin embargo, no es adecuado para todas las situaciones. A menudo todo lo que necesitas es cambiar el estado de 2 o 3 widgets al mismo tiempo, o un cambio efemeral de estado, en cuyo caso la programación reactiva no es mala, pero no es apropiada. + +La programación reactiva tiene un mayor consumo de RAM que puede ser compensado por el flujo de trabajo individual, que asegurará que sólo un widget sea reconstruido y cuando sea necesario, pero crear una lista con 80 objetos, cada uno con varios streams no es una buena idea. Abre el oscurecimiento y comprueba cuánto consume un StreamBuilder, y entenderás lo que estoy tratando de decirte. + +Con eso en mente, creé el simple gestor estatal. Es simple, y eso es exactamente lo que debería exigir de él: actualizar el estado en bloques de una manera sencilla, y de la manera más económica. + +GetBuilder es muy económico en RAM, y apenas hay un enfoque más económico que él (al menos no puedo imaginar uno, si existe, por favor háganoslo saber). + +Sin embargo, GetBuilder sigue siendo un gestor de estado mecánico, necesita llamar update() del mismo modo que necesita llamar notificar a Provider(). + +Hay otras situaciones en las que la programación reactiva es realmente interesante, y no trabajar con ella es lo mismo que reinventar la rueda. Con esto en mente, GetX fue creado para proporcionar todo lo que es más moderno y avanzado en un administrador estatal. Actualiza sólo lo que es necesario y cuando es necesario, si tiene un error y envía 300 cambios de estado simultáneamente, GetX filtrará y actualizará la pantalla sólo si el estado realmente cambia. + +GetX es aún más económico que cualquier otro gestor de estado reactivo, pero consume un poco más de RAM que GetBuilder. Pensando en ello y tratando de maximizar el consumo de recursos que Obx fue creado. A diferencia de GetX y GetBuilder, no podrás inicializar un controlador dentro de un Obx, es sólo un Widget con un StreamSubssubscription que recibe cambios de eventos de sus hijos, eso es todo. Es más económico que GetX, pero pierde en GetBuilder, que era de esperar, ya que es reactivo, y GetBuilder tiene el enfoque más simplista que existe, de almacenar el hashcode de un widget y su StateSetter. Con Obx no necesitas escribir tu tipo de controlador y puedes escuchar el cambio desde múltiples controladores diferentes, pero necesita inicializarse antes, ya sea usando el método de ejemplo al principio de este readme, o usando la clase Bindings. diff --git a/docs/i18n/es/docusaurus-plugin-content-docs/current/utils.md b/docs/i18n/es/docusaurus-plugin-content-docs/current/utils.md new file mode 100644 index 000000000..f5c3e8ffd --- /dev/null +++ b/docs/i18n/es/docusaurus-plugin-content-docs/current/utils.md @@ -0,0 +1,894 @@ +--- +sidebar_position: 4 +--- + +# Utils + +## Internacionalización + +### Traducciones + +Las traducciones se mantienen como un simple mapa del diccionario clave-valor. +Para añadir traducciones personalizadas, crea una clase y extiende `traducciones`. + +```dart +import 'package:get/get.dart'; + +class Messages extends Translations { + @override + Map> get keys => { + 'en_US': { + 'hello': 'Hello World', + }, + 'de_DE': { + 'hello': 'Hallo Welt', + } + }; +} +``` + +#### Usando traducciones + +Simplemente añade `.tr` a la clave especificada y se traducirá, usando el valor actual de `Get.locale` y `Get.fallbackLocale`. + +```dart +Text('title'.tr); +``` + +#### Utilizando la traducción con singular y plural + +```dart +var products = []; +Text('singularKey'.trPlural('pluralKey', products.length, Args)); +``` + +#### Utilizando la traducción con parámetros + +```dart +import 'package:get/get.dart'; + + +Map> get keys => { + 'en_US': { + 'logged_in': 'logged in as @name with email @email', + }, + 'es_ES': { + 'logged_in': 'iniciado sesión como @name con e-mail @email', + } +}; + +Text('logged_in'.trParams({ + 'name': 'Jhon', + 'email': 'jhon@example.com' + })); +``` + +### Locales + +Pasar los parámetros a `GetMaterialApp` para definir la localización y las traducciones. + +```dart +return GetMaterialApp( + translations: Messages(), // your translations + locale: Locale('en', 'US'), // translations will be displayed in that locale + fallbackLocale: Locale('en', 'UK'), // specify the fallback locale in case an invalid locale is selected. +); +``` + +#### Cambiar idioma + +Llama a `Get.updateLocale(locale)` para actualizar la locale. A continuación, las traducciones utilizan automáticamente el nuevo idioma. + +```dart +var locale = Locale('en', 'US'); +Get.updateLocale(locale); +``` + +#### Localización del sistema + +Para leer la configuración regional del sistema, puede utilizar `Get.deviceLocale`. + +```dart +return GetMaterialApp( + locale: Get.deviceLocale, +); +``` + +## Cambiar tema + +Por favor, no utilice ningún widget de nivel superior a `GetMaterialApp` para actualizarlo. Esto puede desencadenar claves duplicadas. Muchas personas están acostumbradas al enfoque prehistórico de crear un widget "ThemeProvider" sólo para cambiar el tema de tu aplicación, y esto definitivamente NO es necesario con **GetXTM**. + +Puedes crear tu tema personalizado y simplemente añadirlo en `Get.changeTheme` sin ningún tipo de aviso para eso: + +```dart +Get.changeTheme(ThemeData.light()); +``` + +Si quieres crear algo como un botón que cambia el tema en `onTap`, puedes combinar dos API **GetXTM** para eso: + +- La api que comprueba si el oscuro `Theme` está siendo usado. +- Y el API de cambio de `Theme`, puedes poner esto dentro de un `onPressed`: + +```dart +Get.changeTheme(Get.isDarkMode? ThemeData.light(): ThemeData.dark()); +``` + +Cuando `.darkmode` está activado, cambiará al _light theme_, y cuando el _light theme_ se activa, cambiará a _tema oscuro_. + +## Conectar + +GetConnect es una forma fácil de comunicarse desde la parte trasera a tu frente con http o websockets + +### Configuración por defecto + +Puede simplemente extender GetConnect y utilizar los métodos GET/POST/PUT/DELETE/SOCKET para comunicarse con su API Rest o websockets. + +```dart +class UserProvider extends GetConnect { + // Get request + Future getUser(int id) => get('http://youapi/users/$id'); + // Post request + Future postUser(Map data) => post('http://youapi/users', body: data); + // Post request with File + Future> postCases(List image) { + final form = FormData({ + 'file': MultipartFile(image, filename: 'avatar.png'), + 'otherFile': MultipartFile(image, filename: 'cover.png'), + }); + return post('http://youapi/users/upload', form); + } + + GetSocket userMessages() { + return socket('https://yourapi/users/socket'); + } +} +``` + +### Configuración personalizada + +GetConnect es altamente personalizable. Puedes definir la Url base, como modificadores de respuesta, como modificadores de peticiones, definen un autenticador, e incluso el número de intentos en los que intentará autoautenticarse. además de dar la posibilidad de definir un decodificador estándar que transformará todas sus peticiones en sus modelos sin ninguna configuración adicional. + +```dart +class HomeProvider extends GetConnect { + @override + void onInit() { + // All request will pass to jsonEncode so CasesModel.fromJson() + httpClient.defaultDecoder = CasesModel.fromJson; + httpClient.baseUrl = 'https://api.covid19api.com'; + // baseUrl = 'https://api.covid19api.com'; // It define baseUrl to + // Http and websockets if used with no [httpClient] instance + + // It's will attach 'apikey' property on header from all requests + httpClient.addRequestModifier((request) { + request.headers['apikey'] = '12345678'; + return request; + }); + + // Even if the server sends data from the country "Brazil", + // it will never be displayed to users, because you remove + // that data from the response, even before the response is delivered + httpClient.addResponseModifier((request, response) { + CasesModel model = response.body; + if (model.countries.contains('Brazil')) { + model.countries.remove('Brazilll'); + } + }); + + httpClient.addAuthenticator((request) async { + final response = await get("http://yourapi/token"); + final token = response.body['token']; + // Set the header + request.headers['Authorization'] = "$token"; + return request; + }); + + //Autenticator will be called 3 times if HttpStatus is + //HttpStatus.unauthorized + httpClient.maxAuthRetries = 3; + } + + @override + Future> getCases(String path) => get(path); +} +``` + +## Obtener Middleware + +GetPage tiene ahora una nueva propiedad que toma una lista de GetMiddleWare y ejecutarlos en el orden específico. + +**Nota**: Cuando GetPage tenga un Middlewares, todos los hijos de esta página tendrán los mismos middlewares automáticamente. + +### Prioridad + +La Orden de los Middlewares a ejecutar puede ser establecida por la prioridad en el GetMiddleware. + +```dart +final middlewares = [ + GetMiddleware(priority: 2), + GetMiddleware(priority: 5), + GetMiddleware(priority: 4), + GetMiddleware(priority: -8), +]; +``` + +esos middlewares se ejecutarán en este orden **-8 => 2 => 4 => 5** + +### Redirigir + +Esta función será llamada cuando se busque la página de la ruta llamada. Se necesita RouteSettings como resultado para redirigirse. O dale nulo y no habrá redireccionamiento. + +```dart +RouteSettings redirect(String route) { + final authService = Get.find(); + return authService.authed.value ? null : RouteSettings(name: '/login') +} +``` + +### en la página llamada + +Esta función se llamará cuando se llame a esta página antes de cualquier cosa creada +puedes usarla para cambiar algo sobre la página o darle una nueva página + +```dart +GetPage onPageCalled(GetPage page) { + final authService = Get.find(); + return page.copyWith(title: 'Welcome ${authService.UserName}'); +} +``` + +### OnBindingsStart + +Esta función se llamará justo antes de que los enlaces sean inicializados. +Aquí puedes cambiar los enlaces para esta página. + +```dart +List onBindingsStart(List bindings) { + final authService = Get.find(); + if (authService.isAdmin) { + bindings.add(AdminBinding()); + } + return bindings; +} +``` + +### Inicio OnPageBuild + +Esta función se llamará justo después de que los enlaces sean inicializados. +Aquí puedes hacer algo después de que hayas creado los enlaces y antes de crear el widget de página. + +```dart +GetPageBuilder onPageBuildStart(GetPageBuilder page) { + print('bindings are ready'); + return page; +} +``` + +### OnPageBuilt + +Esta función será llamada justo después de que la función GetPage.page sea llamada y le dará el resultado de la función. y tome el widget que se mostrará. + +### Disponer en la página + +Esta función se llamará justo después de eliminar todos los objetos relacionados (Controladores, vistas, ...) de la página. + +## Otras API avanzadas + +```dart +// give the current args from currentScreen +Get.arguments + +// give name of previous route +Get.previousRoute + +// give the raw route to access for example, rawRoute.isFirst() +Get.rawRoute + +// give access to Routing API from GetObserver +Get.routing + +// check if snackbar is open +Get.isSnackbarOpen + +// check if dialog is open +Get.isDialogOpen + +// check if bottomsheet is open +Get.isBottomSheetOpen + +// remove one route. +Get.removeRoute() + +// back repeatedly until the predicate returns true. +Get.until() + +// go to next route and remove all the previous routes until the predicate returns true. +Get.offUntil() + +// go to next named route and remove all the previous routes until the predicate returns true. +Get.offNamedUntil() + +//Check in what platform the app is running +GetPlatform.isAndroid +GetPlatform.isIOS +GetPlatform.isMacOS +GetPlatform.isWindows +GetPlatform.isLinux +GetPlatform.isFuchsia + +//Check the device type +GetPlatform.isMobile +GetPlatform.isDesktop +//All platforms are supported independently in web! +//You can tell if you are running inside a browser +//on Windows, iOS, OSX, Android, etc. +GetPlatform.isWeb + + +// Equivalent to : MediaQuery.of(context).size.height, +// but immutable. +Get.height +Get.width + +// Gives the current context of the Navigator. +Get.context + +// Gives the context of the snackbar/dialog/bottomsheet in the foreground, anywhere in your code. +Get.contextOverlay + +// Note: the following methods are extensions on context. Since you +// have access to context in any place of your UI, you can use it anywhere in the UI code + +// If you need a changeable height/width (like Desktop or browser windows that can be scaled) you will need to use context. +context.width +context.height + +// Gives you the power to define half the screen, a third of it and so on. +// Useful for responsive applications. +// param dividedBy (double) optional - default: 1 +// param reducedBy (double) optional - default: 0 +context.heightTransformer() +context.widthTransformer() + +/// Similar to MediaQuery.sizeOf(context); +context.mediaQuerySize() + +/// Similar to MediaQuery.paddingOf(context); +context.mediaQueryPadding() + +/// Similar to MediaQuery.viewPaddingOf(context); +context.mediaQueryViewPadding() + +/// Similar to MediaQuery.viewInsetsOf(context); +context.mediaQueryViewInsets() + +/// Similar to MediaQuery.orientationOf(context); +context.orientation() + +/// Check if device is on landscape mode +context.isLandscape() + +/// Check if device is on portrait mode +context.isPortrait() + +/// Similar to MediaQuery.devicePixelRatioOf(context); +context.devicePixelRatio() + +/// Similar to MediaQuery.textScaleFactorOf(context); +context.textScaleFactor() + +/// Get the shortestSide from screen +context.mediaQueryShortestSide() + +/// True if width be larger than 800 +context.showNavbar() + +/// True if the shortestSide is smaller than 600p +context.isPhone() + +/// True if the shortestSide is largest than 600p +context.isSmallTablet() + +/// True if the shortestSide is largest than 720p +context.isLargeTablet() + +/// True if the current device is Tablet +context.isTablet() + +/// Returns a value according to the screen size +/// can give value for: +/// watch: if the shortestSide is smaller than 300 +/// mobile: if the shortestSide is smaller than 600 +/// tablet: if the shortestSide is smaller than 1200 +/// desktop: if width is largest than 1200 +context.responsiveValue() +``` + +### Configuración global opcional y configuraciones manuales + +GetMaterialApp configura todo para ti, pero si quieres configurar Get manualmente. + +```dart +MaterialApp( + navigatorKey: Get.key, + navigatorObservers: [GetObserver()], +); +``` + +También podrá utilizar su propio Middleware dentro de `GetObserver`, esto no influirá en nada. + +```dart +MaterialApp( + navigatorKey: Get.key, + navigatorObservers: [ + GetObserver(MiddleWare.observer) // Here + ], +); +``` + +Puedes crear _Configuración global_ para `Get`. Simplemente añade `Get.config` a tu código antes de empujar cualquier ruta. +O hazlo directamente en tu `GetMaterialApp` + +```dart +GetMaterialApp( + enableLog: true, + defaultTransition: Transition.fade, + opaqueRoute: Get.isOpaqueRouteDefault, + popGesture: Get.isPopGestureEnable, + transitionDuration: Get.defaultDurationTransition, + defaultGlobalState: Get.defaultGlobalState, +); + +Get.config( + enableLog = true, + defaultPopGesture = true, + defaultTransition = Transitions.cupertino +) +``` + +Opcionalmente puede redirigir todos los mensajes de registro de `Get`. +Si quieres usar tu propio paquete de registro favorito, +y quieres capturar los registros ahí: + +```dart +GetMaterialApp( + enableLog: true, + logWriterCallback: localLogWriter, +); + +void localLogWriter(String text, {bool isError = false}) { + // pass the message to your favourite logging package here + // please note that even if enableLog: false log messages will be pushed in this callback + // you get check the flag if you want through GetConfig.isLogEnable +} + +``` + +### Widgets del estado local + +Estos Widgets te permiten administrar un único valor, y mantener el estado efemeral y localmente. +Tenemos sabores para Reactive y simples. +Por ejemplo, puedes usarlos para alternar obscureText en un `TextField`, tal vez crear un Panel +Personalizable, o tal vez modificar el índice actual en `BottomNavigationBar` cambiando el contenido +del cuerpo en un `Scaffold`. + +#### Constructor de valores + +Una simplificación de `StatefulWidget` que funciona con un callback `.setState` que toma el valor actualizado. + +```dart +ValueBuilder( + initialValue: false, + builder: (value, updateFn) => Switch( + value: value, + onChanged: updateFn, // same signature! you could use ( newValue ) => updateFn( newValue ) + ), + // if you need to call something outside the builder method. + onUpdate: (value) => print("Value updated: $value"), + onDispose: () => print("Widget unmounted"), +), +``` + +#### ObxValue + +Similar a [`ValueBuilder`](#valuebuilder), pero esta es la versión Reactiva, pasas una instancia Rx (¿recuerdas los .obs mágicos?) y +actualizaciones automáticamente... ¿No es increíble? + +```dart +ObxValue((data) => Switch( + value: data.value, + onChanged: data, // Rx has a _callable_ function! You could use (flag) => data.value = flag, + ), + false.obs, +), +``` + +## Consejos útiles + +Los tipos `.obs`ervables (también conocidos como _Rx_ Types) tienen una amplia variedad de métodos y operadores internos. + +> Es muy común _creer_ que una propiedad con `.obs` **IS** el valor real... ¡pero no te equivoques! +> Evitamos la declaración Type de la variable, porque el compilador de Dart es suficientemente inteligente, y el código +> se ve más limpio, pero: + +```dart +var message = 'Hello world'.obs; +print( 'Message "$message" has Type ${message.runtimeType}'); +``` + +¡Incluso si `message` _imprime_ el valor real de cadena, el tipo es **RxString**! + +Así que no puedes hacer `message.substring( 0, 4 )`. +Tienes que acceder al verdadero `valor` dentro del _observable_: +La forma más "utilizada" es `. alue`, pero, ¿sabías que también puedes usar... + +```dart +final name = 'GetX'.obs; +// only "updates" the stream, if the value is different from the current one. +name.value = 'Hey'; + +// All Rx properties are "callable" and returns the new value. +// but this approach does not accepts `null`, the UI will not rebuild. +name('Hello'); + +// is like a getter, prints 'Hello'. +name() ; + +/// numbers: + +final count = 0.obs; + +// You can use all non mutable operations from num primitives! +count + 1; + +// Watch out! this is only valid if `count` is not final, but var +count += 1; + +// You can also compare against values: +count > 2; + +/// booleans: + +final flag = false.obs; + +// switches the value between true/false +flag.toggle(); + + +/// all types: + +// Sets the `value` to null. +flag.nil(); + +// All toString(), toJson() operations are passed down to the `value` +print( count ); // calls `toString()` inside for RxInt + +final abc = [0,1,2].obs; +// Converts the value to a json Array, prints RxList +// Json is supported by all Rx types! +print('json: ${jsonEncode(abc)}, type: ${abc.runtimeType}'); + +// RxMap, RxList and RxSet are special Rx types, that extends their native types. +// but you can work with a List as a regular list, although is reactive! +abc.add(12); // pushes 12 to the list, and UPDATES the stream. +abc[3]; // like Lists, reads the index 3. + + +// equality works with the Rx and the value, but hashCode is always taken from the value +final number = 12.obs; +print( number == 12 ); // prints > true + +/// Custom Rx Models: + +// toJson(), toString() are deferred to the child, so you can implement override on them, and print() the observable directly. + +class User { + String name, last; + int age; + User({this.name, this.last, this.age}); + + @override + String toString() => '$name $last, $age years old'; +} + +final user = User(name: 'John', last: 'Doe', age: 33).obs; + +// `user` is "reactive", but the properties inside ARE NOT! +// So, if we change some variable inside of it... +user.value.name = 'Roi'; +// The widget will not rebuild!, +// `Rx` don't have any clue when you change something inside user. +// So, for custom classes, we need to manually "notify" the change. +user.refresh(); + +// or we can use the `update()` method! +user.update((value){ + value.name='Roi'; +}); + +print( user ); +``` + +## Mixin de estado + +Otra forma de manejar tu estado `UI` es usar el `StateMixin` . +Para implementarlo, usa el `con` para agregar el `StateMixin` +a tu controlador que permite un modelo T. + +```dart +class Controller extends GetController with StateMixin{} +``` + +El método `change()` cambia el Estado siempre que queremos. +Simplemente pase los datos y el estado de esta manera: + +```dart +change(data, status: RxStatus.success()); +``` + +RxStatus permite estos estados: + +```dart +RxStatus.loading(); +RxStatus.success(); +RxStatus.empty(); +RxStatus.error('message'); +``` + +Para representarlo en la interfaz de usuario, use: + +```dart +class OtherClass extends GetView { + @override + Widget build(BuildContext context) { + return Scaffold( + + body: controller.obx( + (state)=>Text(state.name), + + // here you can put your custom loading indicator, but + // by default would be Center(child:CircularProgressIndicator()) + onLoading: CustomLoadingIndicator(), + onEmpty: Text('No data found'), + + // here also you can set your own error widget, but by + // default will be an Center(child:Text(error)) + onError: (error)=>Text(error), + ), + ); +} +``` + +#### GetView + +Me encanta este Widget, es tan simple, pero tan útil! + +Es un Widget `const Stateless` que tiene un getter `controller` para un `Controller` registrado, eso es todo. + +```dart + class AwesomeController extends GetController { + final String title = 'My Awesome View'; + } + + // ALWAYS remember to pass the `Type` you used to register your controller! + class AwesomeView extends GetView { + @override + Widget build(BuildContext context) { + return Container( + padding: EdgeInsets.all(20), + child: Text(controller.title), // just call `controller.something` + ); + } + } +``` + +#### Ver Responsiva + +Extender este widget para crear una vista receptiva. +este widget contiene la propiedad `screen` que tiene toda la información +sobre el tamaño y el tipo de pantalla. + +##### Cómo usarlo + +Tienes dos opciones para construirlo. + +- con el método `builder` devuelve el widget a construir. +- con métodos `desktop`, `tablet`,`phone`, `watch`. el método + específico se construirá cuando el tipo de pantalla coincida con el método + cuando la pantalla sea \[ScreenType.Tablet] el método `tablet` + se existirá, y así sucesivamente. + **Nota:** Si usas este método, por favor establece la propiedad `alwaysUseBuilder` a `false` + +Con la propiedad `settings` puedes establecer el límite de ancho para los tipos de pantalla. + +[example](https://github.com/SchabanBo/get_page_example/blob/master/docs/Example.gif?raw=true) +Código a esta pantalla +[code](https://github.com/SchabanBo/get_page_example/blob/master/lib/pages/responsive_example/responsive_view.dart) + +#### GetWidget + +La mayoría de la gente no tiene ni idea de este Widget, o confunde totalmente el uso de él. +El caso de uso es muy raro, pero muy específico: `caches` un Controller. +Debido a la _cache_, no puede ser un `const Stateless`. + +> Entonces, ¿cuándo necesitas "cache" un Controlador? + +Si usas, otra característica "no tan común" de **GetX**: `Get.create()`. + +`Get.create(()=>Controller())` generará un nuevo `Controller` cada vez que llame +`Get.find()`, + +Ahí es donde brilla `GetWidget`... como puedes usarlo, por ejemplo, +para mantener una lista de elementos de Tarea Así que, si el widget es "reconstruido", mantendrá la misma instancia del controlador. + +#### GetxService + +Esta clase es como un `GetxController`, comparte el mismo ciclo de vida ( `onInit()`, `onReady()`, `onClose()`). +Pero no tiene una "lógica" dentro de ella. Acaba de notificar al sistema de Inyección de Dependencia **GetX**, que esta subclase +**no** puede ser removida de la memoria. + +Así que es super útil para mantener sus "Servicios" siempre accesible y activo con `Get.find()`. Me gusta: +`ApiService`, `StorageService`, `CacheService`. + +```dart +Future main() async { + await initServices(); /// AWAIT SERVICES INITIALIZATION. + runApp(SomeApp()); +} + +/// Is a smart move to make your Services intiialize before you run the Flutter app. +/// as you can control the execution flow (maybe you need to load some Theme configuration, +/// apiKey, language defined by the User... so load SettingService before running ApiService. +/// so GetMaterialApp() doesnt have to rebuild, and takes the values directly. +void initServices() async { + print('starting services ...'); + /// Here is where you put get_storage, hive, shared_pref initialization. + /// or moor connection, or whatever that's async. + await Get.putAsync(() => DbService().init()); + await Get.putAsync(SettingsService()).init(); + print('All services started...'); +} + +class DbService extends GetxService { + Future init() async { + print('$runtimeType delays 2 sec'); + await 2.delay(); + print('$runtimeType ready!'); + return this; + } +} + +class SettingsService extends GetxService { + void init() async { + print('$runtimeType delays 1 sec'); + await 1.delay(); + print('$runtimeType ready!'); + } +} + +``` + +La única forma de eliminar un `GetxService`, es con `Get.reset()` que es como un +"Reinicio caliente" de tu aplicación. Así que recuerda, si necesitas persistencia absoluta de una instancia de clase durante la vida útil de +de tu aplicación, usa `GetxService`. + +### Tests + +Puedes probar tus controladores como cualquier otra clase, incluyendo sus ciclos de vida: + +```dart +class Controller extends GetxController { + @override + void onInit() { + super.onInit(); + //Change value to name2 + name.value = 'name2'; + } + + @override + void onClose() { + name.value = ''; + super.onClose(); + } + + final name = 'name1'.obs; + + void changeName() => name.value = 'name3'; +} + +void main() { + test(''' +Test the state of the reactive variable "name" across all of its lifecycles''', + () { + /// You can test the controller without the lifecycle, + /// but it's not recommended unless you're not using + /// GetX dependency injection + final controller = Controller(); + expect(controller.name.value, 'name1'); + + /// If you are using it, you can test everything, + /// including the state of the application after each lifecycle. + Get.put(controller); // onInit was called + expect(controller.name.value, 'name2'); + + /// Test your functions + controller.changeName(); + expect(controller.name.value, 'name3'); + + /// onClose was called + Get.delete(); + + expect(controller.name.value, ''); + }); +} +``` + +#### Consejos + +##### Mockito o cola de mocktail + +Si necesita simular su GetxController/GetxService, debería extender GetxController, y mezclarlo con Mock, de esa manera + +```dart +class NotificationServiceMock extends GetxService with Mock implements NotificationService {} +``` + +##### Usando Get.reset() + +Si estás probando widgets, o grupos de pruebas, usa Obtener. eset al final de tu prueba o en tearDown para reiniciar todas las configuraciones de tu prueba anterior. + +##### Get.testMode + +si estás usando tu navegación en tus controladores, usa `Get.testMode = true` al principio de tu principal. + +# Rompiendo cambios desde 2.0 + +1- Tipos Rx: + +| Antes | Después | +| -------- | ---------- | +| StringX | `RxString` | +| IntX | `RxInt` | +| MapX | `RxMap` | +| Lista X | `RxList` | +| Número X | `RxNum` | +| DoubleX | `Duplicar` | + +Ahora RxController y GetBuilder se han fusionado, ya no necesita memorizar qué controlador desea utilizar. sólo tiene que utilizar GetxController, funcionará para la gestión simple del estado y también para la reactividad. + +2- Rutas Nombradas +Before: + +```dart +GetMaterialApp( + namedRoutes: { + '/': GetRoute(page: Home()), + } +) +``` + +Ahora: + +```dart +GetMaterialApp( + getPages: [ + GetPage(name: '/', page: () => Home()), + ] +) +``` + +¿Por qué este cambio? +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. +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 permitieron hacer este tipo de método: + +```dart + +GetStorage box = GetStorage(); + +GetMaterialApp( + getPages: [ + GetPage(name: '/', page:(){ + return box.hasData('token') ? Home() : Login(); + }) + ] +) +``` diff --git a/docs/i18n/es/docusaurus-theme-classic/navbar.json b/docs/i18n/es/docusaurus-theme-classic/navbar.json new file mode 100644 index 000000000..ac5792560 --- /dev/null +++ b/docs/i18n/es/docusaurus-theme-classic/navbar.json @@ -0,0 +1,30 @@ +{ + "logo.alt": { + "message": "Logo del sitio", + "description": "The alt text of navbar logo" + }, + "item.label.Get Started": { + "message": "Empezar", + "description": "Navbar item with label Get Started" + }, + "item.label.About": { + "message": "Acerca de", + "description": "Navbar item with label About" + }, + "item.label.Pillars": { + "message": "Pilares", + "description": "Navbar item with label Pillars" + }, + "item.label.Utils": { + "message": "Utils", + "description": "Navbar item with label Utils" + }, + "item.label.Community": { + "message": "Comunidad", + "description": "Navbar item with label Community" + }, + "item.label.Concepts": { + "message": "Conceptos", + "description": "Navbar item with label Concepts" + } +} diff --git a/docs/i18n/fr/code.json b/docs/i18n/fr/code.json new file mode 100644 index 000000000..f0ccf7863 --- /dev/null +++ b/docs/i18n/fr/code.json @@ -0,0 +1,289 @@ +{ + "theme.ErrorPageContent.title": { + "message": "Cette page a planté.", + "description": "The title of the fallback page when the page crashed" + }, + "theme.blog.archive.title": { + "message": "Archive", + "description": "The page & hero title of the blog archive page" + }, + "theme.blog.archive.description": { + "message": "Archive", + "description": "The page & hero description of the blog archive page" + }, + "theme.blog.paginator.navAriaLabel": { + "message": "Navigation des pages de la liste des blogs", + "description": "The ARIA label for the blog pagination" + }, + "theme.blog.paginator.newerEntries": { + "message": "Nouvelles entrées", + "description": "The label used to navigate to the newer blog posts page (previous page)" + }, + "theme.blog.paginator.olderEntries": { + "message": "Anciennes entrées", + "description": "The label used to navigate to the older blog posts page (next page)" + }, + "theme.BackToTopButton.buttonAriaLabel": { + "message": "Retourner vers le haut", + "description": "The ARIA label for the back to top button" + }, + "theme.blog.post.paginator.navAriaLabel": { + "message": "Navigation de la page de publication du blog", + "description": "The ARIA label for the blog posts pagination" + }, + "theme.blog.post.paginator.newerPost": { + "message": "Nouvelle publication", + "description": "The blog post button label to navigate to the newer/previous post" + }, + "theme.blog.post.paginator.olderPost": { + "message": "Ancien message", + "description": "The blog post button label to navigate to the older/next post" + }, + "theme.blog.post.plurals": { + "message": "Un message | Publications{count}", + "description": "Pluralized label for \"{count} posts\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.blog.tagTitle": { + "message": "{nPosts} étiqueté avec \"{tagName}\"", + "description": "The title of the page for a blog tag" + }, + "theme.tags.tagsPageLink": { + "message": "Voir tous les tags", + "description": "The label of the link targeting the tag list page" + }, + "theme.colorToggle.ariaLabel": { + "message": "Basculer entre le mode sombre et le mode clair (actuellement {mode})", + "description": "The ARIA label for the navbar color mode toggle" + }, + "theme.colorToggle.ariaLabel.mode.dark": { + "message": "mode sombre", + "description": "The name for the dark color mode" + }, + "theme.colorToggle.ariaLabel.mode.light": { + "message": "mode lumière", + "description": "The name for the light color mode" + }, + "theme.docs.DocCard.categoryDescription": { + "message": "Articles {count}", + "description": "The default description for a category card in the generated index about how many items this category includes" + }, + "theme.docs.breadcrumbs.navAriaLabel": { + "message": "Fil d'Ariane", + "description": "The ARIA label for the breadcrumbs" + }, + "theme.docs.paginator.navAriaLabel": { + "message": "Pages de documents", + "description": "The ARIA label for the docs pagination" + }, + "theme.docs.paginator.previous": { + "message": "Précédent", + "description": "The label used to navigate to the previous doc" + }, + "theme.docs.paginator.next": { + "message": "Suivant", + "description": "The label used to navigate to the next doc" + }, + "theme.docs.tagDocListPageTitle.nDocsTagged": { + "message": "Un doc étiqueté |{count} docs taggés", + "description": "Pluralized label for \"{count} docs tagged\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.docs.tagDocListPageTitle": { + "message": "{nDocsTagged} with \"{tagName}\"", + "description": "The title of the page for a docs tag" + }, + "theme.docs.versionBadge.label": { + "message": "Version : {versionLabel}" + }, + "theme.docs.versions.unreleasedVersionLabel": { + "message": "Ceci est une documentation non publiée pour la version {siteTitle} {versionLabel}.", + "description": "The label used to tell the user that he's browsing an unreleased doc version" + }, + "theme.docs.versions.unmaintainedVersionLabel": { + "message": "Il s'agit de la documentation pour {siteTitle} {versionLabel}, qui n'est plus activement maintenue.", + "description": "The label used to tell the user that he's browsing an unmaintained doc version" + }, + "theme.docs.versions.latestVersionSuggestionLabel": { + "message": "Pour une documentation à jour, consultez l' {latestVersionLink} ({versionLabel}).", + "description": "The label used to tell the user to check the latest version" + }, + "theme.docs.versions.latestVersionLinkLabel": { + "message": "dernière version", + "description": "The label used for the latest version suggestion link label" + }, + "theme.common.editThisPage": { + "message": "Modifier cette page", + "description": "The link label to edit the current page" + }, + "theme.common.headingLinkTitle": { + "message": "Lien direct vers {heading}", + "description": "Title for link to heading" + }, + "theme.lastUpdated.atDate": { + "message": " sur {date}", + "description": "The words used to describe on which date a page has been last updated" + }, + "theme.lastUpdated.byUser": { + "message": " par {user}", + "description": "The words used to describe by who the page has been last updated" + }, + "theme.lastUpdated.lastUpdatedAtBy": { + "message": "Dernière mise à jour{atDate}{byUser}", + "description": "The sentence used to display when a page has been last updated, and by who" + }, + "theme.NotFound.title": { + "message": "Page introuvable", + "description": "The title of the 404 page" + }, + "theme.navbar.mobileVersionsDropdown.label": { + "message": "Versions", + "description": "The label for the navbar versions dropdown on mobile view" + }, + "theme.tags.tagsListLabel": { + "message": "Tags :", + "description": "The label alongside a tag list" + }, + "theme.AnnouncementBar.closeButtonAriaLabel": { + "message": "Fermer", + "description": "The ARIA label for close button of announcement bar" + }, + "theme.admonition.caution": { + "message": "précaution", + "description": "The default label used for the Caution admonition (:::caution)" + }, + "theme.admonition.danger": { + "message": "Le danger", + "description": "The default label used for the Danger admonition (:::danger)" + }, + "theme.admonition.info": { + "message": "Infos", + "description": "The default label used for the Info admonition (:::info)" + }, + "theme.admonition.note": { + "message": "note", + "description": "The default label used for the Note admonition (:::note)" + }, + "theme.admonition.tip": { + "message": "tip", + "description": "The default label used for the Tip admonition (:::tip)" + }, + "theme.admonition.warning": { + "message": "avertissement", + "description": "The default label used for the Warning admonition (:::warning)" + }, + "theme.blog.sidebar.navAriaLabel": { + "message": "Navigation des articles récents dans le blog", + "description": "The ARIA label for recent posts in the blog sidebar" + }, + "theme.CodeBlock.copied": { + "message": "Copié", + "description": "The copied button label on code blocks" + }, + "theme.CodeBlock.copyButtonAriaLabel": { + "message": "Copier le code dans le presse-papiers", + "description": "The ARIA label for copy code blocks button" + }, + "theme.CodeBlock.copy": { + "message": "Copie", + "description": "The copy button label on code blocks" + }, + "theme.CodeBlock.wordWrapToggle": { + "message": "Afficher/Masquer les mots", + "description": "The title attribute for toggle word wrapping button of code block lines" + }, + "theme.DocSidebarItem.expandCategoryAriaLabel": { + "message": "Développer la catégorie de la barre latérale '{label}'", + "description": "The ARIA label to expand the sidebar category" + }, + "theme.DocSidebarItem.collapseCategoryAriaLabel": { + "message": "Réduire la catégorie de la barre latérale '{label}'", + "description": "The ARIA label to collapse the sidebar category" + }, + "theme.NavBar.navAriaLabel": { + "message": "Principal", + "description": "The ARIA label for the main navigation" + }, + "theme.NotFound.p1": { + "message": "Nous n'avons pas trouvé ce que vous cherchiez.", + "description": "The first paragraph of the 404 page" + }, + "theme.NotFound.p2": { + "message": "Veuillez contacter le propriétaire du site qui vous a lié à l'URL d'origine et leur faire savoir que leur lien est cassé.", + "description": "The 2nd paragraph of the 404 page" + }, + "theme.navbar.mobileLanguageDropdown.label": { + "message": "Langues", + "description": "The label for the mobile language switcher dropdown" + }, + "theme.blog.post.readMore": { + "message": "En savoir plus", + "description": "The label used in blog post item excerpts to link to full blog posts" + }, + "theme.blog.post.readMoreLabel": { + "message": "En savoir plus sur {title}", + "description": "The ARIA label for the link to full blog posts from excerpts" + }, + "theme.blog.post.readingTime.plurals": { + "message": "Lecture d'une minute |{readingTime} min de lecture", + "description": "Pluralized label for \"{readingTime} min read\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.docs.breadcrumbs.home": { + "message": "Page d'accueil", + "description": "The ARIA label for the home page in the breadcrumbs" + }, + "theme.docs.sidebar.collapseButtonTitle": { + "message": "Réduire la barre latérale", + "description": "The title attribute for collapse button of doc sidebar" + }, + "theme.docs.sidebar.collapseButtonAriaLabel": { + "message": "Réduire la barre latérale", + "description": "The title attribute for collapse button of doc sidebar" + }, + "theme.docs.sidebar.navAriaLabel": { + "message": "Docs sidebar", + "description": "The ARIA label for the sidebar navigation" + }, + "theme.TOCCollapsible.toggleButtonLabel": { + "message": "Sur cette page", + "description": "The label used by the button on the collapsible TOC component" + }, + "theme.docs.sidebar.expandButtonTitle": { + "message": "Expand sidebar", + "description": "The ARIA label and title attribute for expand button of doc sidebar" + }, + "theme.docs.sidebar.expandButtonAriaLabel": { + "message": "Expand sidebar", + "description": "The ARIA label and title attribute for expand button of doc sidebar" + }, + "theme.docs.sidebar.closeSidebarButtonAriaLabel": { + "message": "Fermer la barre de navigation", + "description": "The ARIA label for close button of mobile sidebar" + }, + "theme.docs.sidebar.toggleSidebarButtonAriaLabel": { + "message": "Basculer la barre de navigation", + "description": "The ARIA label for hamburger menu button of mobile navigation" + }, + "theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel": { + "message": " Retour au menu principal", + "description": "The label of the back button to return to main menu, inside the mobile navbar sidebar secondary menu (notably used to display the docs sidebar)" + }, + "theme.ErrorPageContent.tryAgain": { + "message": "Réessayez", + "description": "The label of the button to try again rendering when the React error boundary captures an error" + }, + "theme.common.skipToMainContent": { + "message": "Passer au contenu principal", + "description": "The skip to content label used for accessibility, allowing to rapidly navigate to main content with keyboard tab/enter navigation" + }, + "theme.tags.tagsPageTitle": { + "message": "Tags", + "description": "The title of the tag list page" + }, + "theme.unlistedContent.title": { + "message": "Page non listée", + "description": "The unlisted content banner title" + }, + "theme.unlistedContent.message": { + "message": "Cette page n'est pas répertoriée. Les moteurs de recherche ne l'indexeront pas, et seuls les utilisateurs ayant un lien direct peuvent y accéder.", + "description": "The unlisted content banner message" + } +} diff --git a/docs/i18n/fr/docusaurus-plugin-content-blog/options.json b/docs/i18n/fr/docusaurus-plugin-content-blog/options.json new file mode 100644 index 000000000..c42ac253d --- /dev/null +++ b/docs/i18n/fr/docusaurus-plugin-content-blog/options.json @@ -0,0 +1,14 @@ +{ + "title": { + "message": "Blogue", + "description": "The title for the blog used in SEO" + }, + "description": { + "message": "Blogue", + "description": "The description for the blog used in SEO" + }, + "sidebar.title": { + "message": "Messages récents", + "description": "The label for the left sidebar" + } +} diff --git a/docs/i18n/fr/docusaurus-plugin-content-docs/current.json b/docs/i18n/fr/docusaurus-plugin-content-docs/current.json new file mode 100644 index 000000000..7c4afc036 --- /dev/null +++ b/docs/i18n/fr/docusaurus-plugin-content-docs/current.json @@ -0,0 +1,30 @@ +{ + "version.label": { + "message": "Suivant", + "description": "The label for version current" + }, + "sidebar.tutorialSidebar.category.The 3 Pillars": { + "message": "Les 3 piliers", + "description": "The label for category The 3 Pillars in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.The 3 Pillars.link.generated-index.description": { + "message": "Les 3 piliers de GetX.", + "description": "The generated-index page description for category The 3 Pillars in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.Community": { + "message": "Communauté", + "description": "The label for category Community in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.Community.link.generated-index.description": { + "message": "Communauté", + "description": "The generated-index page description for category Community in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.Concepts": { + "message": "Concepts", + "description": "The label for category Concepts in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.Concepts.link.generated-index.description": { + "message": "Les concepts des 3 piliers de GetX.", + "description": "The generated-index page description for category Concepts in sidebar tutorialSidebar" + } +} diff --git a/docs/i18n/fr/docusaurus-plugin-content-docs/current/about.md b/docs/i18n/fr/docusaurus-plugin-content-docs/current/about.md new file mode 100644 index 000000000..5f6da5810 --- /dev/null +++ b/docs/i18n/fr/docusaurus-plugin-content-docs/current/about.md @@ -0,0 +1,44 @@ +--- +sidebar_position: 2 +--- + +# À propos de GetX + +- GetX est une solution extrêmement légère et puissante pour Flutter. Il combine la gestion de l'état de haute performance, l'injection intelligente de dépendances et la gestion des routes rapidement et pratiquement. + +- GetX a 3 principes de base. Cela signifie qu'il s'agit de la priorité pour toutes les ressources de la bibliothèque : **PRODUCTIVITÉ, PERFORMANCE ET ORGANISATION.** + + - **PERFORMANCE :** GetX se concentre sur les performances et la consommation minimale des ressources. GetX n'utilise ni Streams ni ChangeNotifier. + + - **PRODUCTIVITÉ:** GetX utilise une syntaxe facile et agréable. Peu importe ce que vous voulez faire, il y a toujours un moyen plus simple avec GetX. Cela vous permettra de gagner des heures de développement et de fournir les performances maximales que votre application peut offrir. + + Généralement, le développeur devrait se soucier de supprimer les contrôleurs de la mémoire. Avec GetX, ce n'est pas nécessaire car les ressources sont retirées de la mémoire quand elles ne sont pas utilisées par défaut. Si vous voulez le conserver en mémoire, vous devez déclarer explicitement "permanent: true" dans votre dépendance. De cette façon, en plus de gagner du temps, vous risquez moins d'avoir des dépendances inutiles sur la mémoire. Le chargement des dépendances est également paresseux par défaut. + + - **ORGANISATION :** GetX permet le découplage total de la vue, de la logique de présentation, de la logique métier, de l'injection de dépendances et de la navigation. Vous n'avez pas besoin de contexte pour naviguer entre les routes, donc vous n'êtes pas dépendant de l'arborescence des widgets (visualisation) pour cela. Vous n'avez pas besoin de contexte pour accéder à vos contrôleurs/blocs à travers un héritedWidget, donc vous déconnectez complètement votre logique de présentation et votre logique métier de votre calque de visualisation. Vous n'avez pas besoin d'injecter vos classes Controllers/Models/Blocs dans votre arborescence de widgets via `MultiProvider`s. Pour cela, GetX utilise sa propre fonction d'injection de dépendance, découplant complètement le DI de sa vue. + + Avec GetX, vous savez où trouver chaque fonctionnalité de votre application, avec du code propre par défaut. En plus de faciliter la maintenance, cela rend le partage de modules quelque chose qui, jusque-là, dans Flutter était impensable, quelque chose de totalement possible. + BLoC a été un point de départ pour organiser le code dans Flutter, il sépare la logique commerciale de la visualisation. GetX est une évolution naturelle de cela, non seulement en séparant la logique commerciale mais aussi la logique de présentation. Les injections supplémentaires de dépendances et de routes sont également découplées, et la couche de données est hors de tout. Vous savez où tout se trouve, et tout cela d'une manière plus facile que de construire un monde de bonjour. + GetX est la façon la plus facile, pratique et évolutive de construire des applications hautes performances avec le Flutter SDK. Il a un grand écosystème autour de lui qui fonctionne parfaitement ensemble, il est facile pour les débutants, et il est précis pour les experts. Il est sécurisé, stable, à jour et offre une vaste gamme d'API intégrées qui ne sont pas présentes dans le SDK Flutter par défaut. + +- GetX n'est pas gonflé. Il a une multitude de fonctionnalités qui vous permettent de commencer à programmer sans vous soucier de quoi que ce soit, mais chacune de ces fonctionnalités est dans des conteneurs séparés et ne démarre qu'après utilisation. Si vous n'utilisez que la gestion d'Etat, seule la gestion d'Etat sera compilée. Si vous n'utilisez que des routes, rien de la gestion de l'État ne sera compilé. + +- GetX a un énorme écosystème, une grande communauté, un grand nombre de collaborateurs, et sera maintenu tant que le Flutter existe. GetX aussi est capable d'exécuter avec le même code sur Android, iOS, Web, Mac, Linux, Windows et sur votre serveur. + **Il est possible de réutiliser complètement votre code fait sur le frontend de votre backend avec [Get Server](https://github.com/jonataslaw/get_server)**. + +**De plus, l'ensemble du processus de développement peut être entièrement automatisé, tant sur le serveur que sur le front-end avec [Get CLI](https://github.com/jonataslaw/get_cli)**. + +**En outre, pour augmenter votre productivité, nous avons l'extension +[pour VSCode](https://marketplace.visualstudio.com/items?itemName=get-snippets.get-snippets) et [l'extension pour Android Studio/Intellij](https://plugins.jetbrains.com/plugin/14975-getx-snippets)** + +## Pourquoi Getx ? + +1- Plusieurs fois après une mise à jour de Flut, beaucoup de vos paquets vont se briser. Parfois, des erreurs de compilation se produisent, des erreurs apparaissent souvent qu'il n'y a toujours aucune réponse, et le développeur a besoin de savoir d'où vient l'erreur, suivre l'erreur, puis essayer d'ouvrir un problème dans le référentiel correspondant, et voir son problème résolu. Permet de centraliser les principales ressources de développement (gestion de l'état, de la dépendance et de la route), vous permettant d'ajouter un seul paquet à votre pubspec, et de commencer à travailler. Après une mise à jour de Fluard, la seule chose à faire est de mettre à jour la dépendance Get et de se mettre au travail. Obtenir résout également les problèmes de compatibilité. Combien de fois une version d'un paquet n'est pas compatible avec la version d'un autre, parce que l'on utilise une dépendance dans une version, et l'autre dans une autre version ? Ce n'est pas non plus une préoccupation en utilisant Get, car tout est dans le même paquet et est entièrement compatible. + +2- Flutter est facile, Flutter est incroyable, mais Flutter a encore quelques boilerplate qui peuvent être indésirables pour la plupart des développeurs, comme `Navigator. f(context).push (contexte, constructeur [...]`. Obtenir simplifie le développement. Au lieu d'écrire 8 lignes de code pour simplement appeler une route, tu peux juste le faire: `Get. o(Home())` et vous avez terminé, vous allez à la page suivante. Les URL web dynamiques sont une chose vraiment douloureuse à faire avec Flutter actuellement, et cela avec GetX est stupidement simple. La gestion des états dans Flutter, et la gestion des dépendances est également quelque chose qui génère beaucoup de discussions, car il y a des centaines de modèles dans le pub. Mais il n'y a rien d'aussi facile que d'ajouter un ". bs" à la fin de votre variable, et placez votre widget à l'intérieur d'un Obx, et c'est ça, toutes les mises à jour de cette variable seront automatiquement mises à jour à l'écran. + +3- Faciliter sans se soucier des performances. Les performances de Flutter sont déjà incroyables, mais imaginez que vous utilisiez un gestionnaire d'état, et un localisateur pour distribuer vos classes de blocs/magasins/contrôleurs/etc. Vous devrez appeler manuellement l'exclusion de cette dépendance lorsque vous n'en avez pas besoin. Mais avez-vous déjà pensé à utiliser votre contrôleur, et quand il n'était plus utilisé par personne, il serait tout simplement supprimé de la mémoire ? C'est ce que fait GetX. Avec SmartManagement, tout ce qui n'est pas utilisé est supprimé de la mémoire, et vous ne devriez vous soucier que de la programmation. Vous serez assurés que vous consommez les ressources minimales nécessaires, sans même avoir créé une logique pour cela. + +4- Le découplage effectif. Vous avez peut-être entendu le concept "séparer le point de vue de la logique commerciale". Ce n'est pas une particularité de BLoC, MVC, MVVM, et toute autre norme sur le marché a ce concept. Cependant, ce concept peut souvent être atténué dans Flutter en raison de l'utilisation du contexte. +Si vous avez besoin d'un contexte pour trouver un Widget Inhérité, vous en avez besoin dans la vue, ou passez le contexte par paramètre. Je trouve particulièrement cette solution très moche et pour travailler en équipe, nous dépendrons toujours de la logique commerciale de Views. Getx n'est pas orthodoxe avec l'approche standard, et bien qu'il ne bannisse pas complètement l'utilisation de StatefulWidgets, InitState, etc. elle a toujours une approche similaire qui peut être plus propre. Les contrôleurs ont des cycles de vie, et lorsque vous avez besoin de faire une demande APIREST par exemple, vous ne dépendez pas de quoi que ce soit dans la vue. Vous pouvez utiliser onInit pour lancer un appel http et quand les données arrivent, les variables seront remplies. Comme GetX est complètement réactif (vraiment, et fonctionne sous les streams), une fois que les éléments sont remplis, tous les widgets qui utilisent cette variable seront automatiquement mis à jour dans la vue. Cela permet aux personnes possédant l'expertise de l'interface de travailler uniquement avec des widgets, et ne pas avoir à envoyer quoi que ce soit à la logique commerciale autre que les événements utilisateur (comme cliquer sur un bouton), tandis que les personnes travaillant avec la logique commerciale seront libres de créer et de tester la logique commerciale séparément. + +Cette bibliothèque sera toujours mise à jour et en implémentant de nouvelles fonctionnalités. N’hésitez pas à proposer des RP et à y contribuer. diff --git a/docs/i18n/fr/docusaurus-plugin-content-docs/current/community/_category_.json b/docs/i18n/fr/docusaurus-plugin-content-docs/current/community/_category_.json new file mode 100644 index 000000000..d28647647 --- /dev/null +++ b/docs/i18n/fr/docusaurus-plugin-content-docs/current/community/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "Communauté", + "position": 10, + "link": { + "type": "index-généré", + "description": "Communauté" + } +} diff --git a/docs/i18n/fr/docusaurus-plugin-content-docs/current/community/channels.md b/docs/i18n/fr/docusaurus-plugin-content-docs/current/community/channels.md new file mode 100644 index 000000000..5b658e332 --- /dev/null +++ b/docs/i18n/fr/docusaurus-plugin-content-docs/current/community/channels.md @@ -0,0 +1,7 @@ +# Canaux + +GetX a une communauté très active et utile. Si vous avez des questions, ou si vous souhaitez une aide concernant l'utilisation de ce cadre, rejoignez les canaux de la communauté, votre question sera traitée plus rapidement, et ce sera l'endroit le plus approprié. Ce dépôt est exclusif à l'ouverture des problèmes et à la demande de ressources, mais n'hésitez pas à faire partie de la communauté GetX. + +| **Slack** | **Discord** | **Télégramme** | +| :-------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------- | +| [![Get on Slack](https://img.shields.io/badge/slack-join-orange.svg)](https://communityinviter.com/apps/getxworkspace/getx) | [![Discord Shield](https://img.shields.io/discord/722900883784073290.svg?logo=discord)](https://discord.com/invite/9Hpt99N) | [![Telegram](https://img.shields.io/badge/chat-on%20Telegram-blue.svg)](https://t.me/joinchat/PhdbJRmsZNpAqSLJL6bH7g) | diff --git a/docs/i18n/fr/docusaurus-plugin-content-docs/current/community/contribute.md b/docs/i18n/fr/docusaurus-plugin-content-docs/current/community/contribute.md new file mode 100644 index 000000000..54b701015 --- /dev/null +++ b/docs/i18n/fr/docusaurus-plugin-content-docs/current/community/contribute.md @@ -0,0 +1,11 @@ +# Comment contribuer + +_Vous voulez contribuer au projet ? Nous serons fiers de vous présenter comme l'un de nos collaborateurs. Voici quelques points où vous pouvez contribuer et rendre Get (et Flutter) encore meilleur._ + +- Aider à traduire le readme dans d'autres langues. +- Ajout de la documentation à readme (un grand nombre de fonctions de Get's n'ont pas encore été documentées). +- Écrivez des articles ou faites des vidéos enseignant à utiliser Get (ils seront insérés dans le Lisez-moi et dans le futur dans notre Wiki). +- Proposition de PRs pour les code/tests. +- Inclure de nouvelles fonctions. + +Toute contribution est la bienvenue! diff --git a/docs/i18n/fr/docusaurus-plugin-content-docs/current/community/resources.md b/docs/i18n/fr/docusaurus-plugin-content-docs/current/community/resources.md new file mode 100644 index 000000000..d1b060dcf --- /dev/null +++ b/docs/i18n/fr/docusaurus-plugin-content-docs/current/community/resources.md @@ -0,0 +1,21 @@ +# Ressource + +### Articles et vidéos + +- [Flutter Getx EcoSystem package for arabic people](https://www.youtube.com/playlist?list=PLV1fXIAyjeuZ6M8m56zajMUwu4uE3-SL0) - Tutoriel par [Pesa Coder](https://github.com/UsamaElgendy). +- [Thèmes dynamiques en 3 lignes en utilisant GetXTM](https://medium.com/swlh/flutter-dynamic-themes-in-3-lines-c3b375f292e3) - Tutoriel par [Rod Brown](https://github.com/RodBr). +- [Complete GetXTM Navigation](https://www.youtube.com/watch?v=RaqPIoJSTtI) - Vidéo de gestion de route par Amateur Coder. +- [Complete GetX State Management](https://www.youtube.com/watch?v=CNpXbeI_slw) - Vidéo de gestion d'état par Amateur Coder. +- [GetXTM Autres fonctionnalités](https://youtu.be/ttQtlX_Q0eU) - Utils, stockage, bindings et autres fonctionnalités vidéo par Amateur Coder. +- [Firestore User with GetX | Todo App](https://www.youtube.com/watch?v=BiV0DcXgk58) - Vidéo par Amateur Coder. +- [Firebase Auth with GetX | Todo App](https://www.youtube.com/watch?v=-H-T_BSgfOE) - Vidéo par Amateur Coder. +- [The Flutter GetXTM Ecosystem \~ State Management](https://medium.com/flutter-community/the-flutter-getx-ecosystem-state-management-881c7235511d) - State management by [Aachman Garg](https://github.com/imaachman). +- [The Flutter GetXTM Ecosystem \~ Dependency Injection](https://medium.com/flutter-community/the-flutter-getx-ecosystem-dependency-injection-8e763d0ec6b9) - Dependency Injection by [Aachman Garg](https://github.com/imaachman). +- [GetX, le package Flutter tout-en-un](https://www.youtube.com/watch?v=IYQgtu9TM74) - Un bref tutoriel sur la gestion de l'État et la navigation par Thad Carnevalli. +- [Construire une application de liste de tâches à partir de zéro en utilisant Flutter et GetX](https://www.youtube.com/watch?v=EcnqFasHf18) - UI + State Management + Storage video par Thad Carnevalli. +- [GetX Flutter Firebase Auth Exempple](https://medium.com/@jeffmcmorris/getx-flutter-firebase-auth-example-b383c1dd1de2) - Article de Jeff McMorris. +- [Flutter State Management avec GetX - Application complète](https://www.appwithflutter.com/flutter-state-management-with-getx/) - par App With Flutter. +- [Flutter Routing with Animation using Get Package](https://www.appwithflutter.com/flutter-routing-using-get-package/) - par App With Flutter. +- [Un exemple minimal sur dartpad](https://dartpad.dev/2b3d0d6f9d4e312c5fdbefc414c1727e?) - par [Roi Peker](https://github.com/roipeker) +- [GetConnect: Le meilleur moyen d'effectuer des opérations API avec Get.](https://absyz.com/getconnect-the-best-way-to-perform-api-operations-in-flutter-with-getx/) - par [MD Sarfaraj](https://github.com/socialmad) +- [Comment créer une application avec GetX Architect en Flutter avec Get CLI](https://www.youtube.com/watch?v=7mb4qBA7kTk\&t=1380s) - par [MD Sarfaraj](https://github.com/socialmad) diff --git a/docs/i18n/fr/docusaurus-plugin-content-docs/current/concepts/_category_.json b/docs/i18n/fr/docusaurus-plugin-content-docs/current/concepts/_category_.json new file mode 100644 index 000000000..609fd0dda --- /dev/null +++ b/docs/i18n/fr/docusaurus-plugin-content-docs/current/concepts/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "Concepts", + "position": 3, + "link": { + "type": "index-généré", + "description": "Les concepts des 3 piliers de GetX." + } +} diff --git a/docs/i18n/fr/docusaurus-plugin-content-docs/current/concepts/dependency-management.md b/docs/i18n/fr/docusaurus-plugin-content-docs/current/concepts/dependency-management.md new file mode 100644 index 000000000..bbb3a329b --- /dev/null +++ b/docs/i18n/fr/docusaurus-plugin-content-docs/current/concepts/dependency-management.md @@ -0,0 +1,39 @@ +--- +sidebar_position: 3 +--- + +# Gestion des dépendances + +Get a un gestionnaire de dépendances simple et puissant qui vous permet de récupérer la même classe que votre Bloc ou contrôleur avec seulement 1 ligne de code, pas de contexte de fournisseur, pas de Widget hérité : + +```dart +Controller controller = Get.put(Controller()); // Rather Controller controller = Controller(); +``` + +- Note: Si vous utilisez Get's State Manager, prêtez plus d'attention à l'API de liaisons, qui facilitera la connexion de votre vue à votre contrôleur. + +Au lieu d'instancier votre classe dans la classe que vous utilisez, vous l'instanciez dans l'instance Get qui le rendra disponible dans votre application. +Vous pouvez donc utiliser votre contrôleur (ou votre classe Bloc) normalement + +**Conseil:** Obtenir la gestion des dépendances est découplé des autres parties du paquet, donc si par exemple, votre application utilise déjà un gestionnaire d'état (n'importe qui, n'importe quel, cela n'a aucune importance), vous n'avez pas besoin de tout réécrire, vous pouvez utiliser cette injection de dépendance sans aucun problème + +```dart +controller.fetchApi(); +``` + +Imaginez que vous ayez parcouru de nombreux itinéraires, et que vous ayez besoin de données laissées derrière vous dans votre contrôleur, vous auriez besoin d'un gestionnaire d'état combiné avec le Provider ou Get\_it, correct ? Pas avec Get. Il vous suffit de demander à Get to "find" pour votre contrôleur, vous n'avez pas besoin de dépendances supplémentaires : + +```dart +Controller controller = Get.find(); +//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. +``` + +Et puis vous serez en mesure de récupérer les données de votre contrôleur qui y ont été obtenues : + +```dart +Text(controller.textFromApi); +``` + +### Plus de détails sur la gestion des dépendances + +**Voir une explication plus détaillée de la gestion des dépendances [here](/docs/pillars/dependency-management)** diff --git a/docs/i18n/fr/docusaurus-plugin-content-docs/current/concepts/route-management.md b/docs/i18n/fr/docusaurus-plugin-content-docs/current/concepts/route-management.md new file mode 100644 index 000000000..b2c9f80c5 --- /dev/null +++ b/docs/i18n/fr/docusaurus-plugin-content-docs/current/concepts/route-management.md @@ -0,0 +1,53 @@ +--- +sidebar_position: 2 +--- + +# Gestion de la route + +Si vous allez utiliser des routes/snackbars/dialogs/bottomsheets sans contexte, GetX est excellent pour vous aussi, il suffit de le voir : + +Ajouter "Obtenir" avant votre MaterialApp, la transformer en GetMaterialApp + +```dart +GetMaterialApp( // Before: MaterialApp( + home: MyHome(), +) +``` + +Naviguer vers un nouvel écran : + +```dart + +Get.to(NextScreen()); +``` + +Naviguez vers le nouvel écran avec le nom. Voir plus de détails sur les routes [here](/docs/pillars/route-management#navigation-with-named-routes) + +```dart + +Get.toNamed('/details'); +``` + +Pour fermer les barres de collation, les dialogues, les feuilles du bas ou tout ce que vous fermeriez normalement avec Navigator.pop(contexte); + +```dart +Get.back(); +``` + +Pour passer à l'écran suivant et aucune option pour revenir à l'écran précédent (pour utiliser dans SplashScreens, les écrans de connexion, etc.) + +```dart +Get.off(NextScreen()); +``` + +Pour aller à l'écran suivant et annuler tous les itinéraires précédents (utiles dans les paniers, les sondages et les tests) + +```dart +Get.offAll(NextScreen()); +``` + +Vous avez remarqué que vous n'avez pas à utiliser le contexte pour faire l'une de ces choses ? C'est l'un des plus grands avantages de la gestion de route Get . Avec cela, vous pouvez exécuter toutes ces méthodes à partir de votre classe de contrôleur, sans soucis. + +### Plus de détails sur la gestion de l'itinéraire + +**Travaillez avec des routes nommées et offre également un contrôle de niveau inférieur sur vos routes! Il y a une documentation approfondie [here](/docs/pillars/route-management)** diff --git a/docs/i18n/fr/docusaurus-plugin-content-docs/current/concepts/state-management.md b/docs/i18n/fr/docusaurus-plugin-content-docs/current/concepts/state-management.md new file mode 100644 index 000000000..a08bf9d68 --- /dev/null +++ b/docs/i18n/fr/docusaurus-plugin-content-docs/current/concepts/state-management.md @@ -0,0 +1,47 @@ +--- +sidebar_position: 1 +--- + +# Gestion des états + +Get a deux gestionnaires d'état différents : le simple gestionnaire d'état (nous l'appellerons GetBuilder) et le gestionnaire d'état réactif (GetX/Obx) + +### Gestionnaire d'état réactif + +La programmation réactive peut aliéner de nombreuses personnes parce que l'on dit qu'elle est compliquée. GetX transforme la programmation réactive en quelque chose de assez simple : + +- Vous n'aurez pas besoin de créer des StreamControllers. +- Vous n'aurez pas besoin de créer un StreamBuilder pour chaque variable +- Vous n'aurez pas besoin de créer une classe pour chaque état. +- Vous n'aurez pas besoin de créer un get pour une valeur initiale. +- Vous n'aurez pas besoin d'utiliser des générateurs de code + +La programmation réactive avec Get est aussi simple que l'utilisation de setState. + +Imaginons que vous ayez une variable de nom et que chaque fois que vous la modifiez, tous les widgets qui l'utilisent sont automatiquement changés. + +Ceci est votre variable de compte: + +```dart +var name = 'Jonatas Borges'; +``` + +Pour le rendre observable, il vous suffit d'ajouter ".obs" à la fin de celui-ci : + +```dart +var name = 'Jonatas Borges'.obs; +``` + +Et dans l'interface utilisateur, quand vous voulez afficher cette valeur et mettre à jour l'écran chaque fois que les valeurs changent, faites simplement ceci: + +```dart +Obx(() => Text("${controller.name}")); +``` + +C'est tout. C'est _cel_ simple. + +### Plus de détails sur la gestion des états + +**Voir une explication plus détaillée de la gestion des états [here](/docs/pillars/state-management). Vous y verrez plus d'exemples ainsi que la différence entre le simple gestionnaire d'état et le gestionnaire d'état réactif** + +Vous aurez une bonne idée de la puissance de GetX. diff --git a/docs/i18n/fr/docusaurus-plugin-content-docs/current/intro.md b/docs/i18n/fr/docusaurus-plugin-content-docs/current/intro.md new file mode 100644 index 000000000..f4f619a1c --- /dev/null +++ b/docs/i18n/fr/docusaurus-plugin-content-docs/current/intro.md @@ -0,0 +1,94 @@ +--- +sidebar_position: 1 +--- + +# Commencer + +## Tests en cours + +### Installation en cours + +Ajouter à votre fichier pubspec.yaml : + +```yml +dependencies: + get: +``` + +Importer dans les fichiers qu'il sera utilisé : + +```dart +import 'package:get/get.dart'; +``` + +### Compteur d'application avec GetX + +Le projet "compteur" créé par défaut sur le nouveau projet sur Flutter a plus de 100 lignes (avec commentaires). Pour montrer la puissance de Get, je vais montrer comment faire un "compteur" en changeant l'état à chaque clic, basculer entre les pages et partager l'état entre les écrans, de façon organisée, séparant la logique commerciale de la vue, en SEULEMENT 26 Lignes CODE INCLUANT LES COMMENTS. + +- Étape 1 : + Ajouter "Obtenir" avant votre MaterialApp, en la transformant en GetMaterialApp + +```dart +void main() => runApp(GetMaterialApp(home: Home())); +``` + +- Remarque : cela ne modifie pas le MaterialApp du Flutter, GetMaterialApp n'est pas une application matérielle modifiée, il s'agit juste d'un Widget pré-configuré, qui a le MaterialApp par défaut en tant qu'enfant. Vous pouvez configurer cela manuellement, mais ce n'est absolument pas nécessaire. GetMaterialApp va créer des routes, les injecter, injecter des traductions, injecter tout ce dont vous avez besoin pour la navigation sur route. Si vous utilisez Get uniquement pour la gestion des états ou la gestion des dépendances, il n'est pas nécessaire d'utiliser GetMaterialApp. GetMaterialApp est nécessaire pour les routes, snackbars, internationalisation, bottomSheets, dialogues et apis de haut niveau liés aux routes et à l'absence de contexte. + +- Note2: Cette étape n'est nécessaire que si vous allez utiliser la gestion des routes (`Get.to()`, `Get.back()` et ainsi de suite). Si vous ne allez pas l'utiliser, alors il n'est pas nécessaire de faire l'étape 1 + +- Étape 2: + Créez votre classe de logique métier et placez toutes les variables, méthodes et contrôleurs à l'intérieur. + Vous pouvez rendre n'importe quelle variable observable en utilisant un simple ".obs". + +```dart +class Controller extends GetxController{ + var count = 0.obs; + increment() => count++; +} +``` + +- Étape 3: + Créez votre vue, utilisez StatelessWidget et enregistrez de la RAM, avec Get vous n'aurez peut-être plus besoin d'utiliser StatefulWidget. + +```dart +class Home extends StatelessWidget { + + @override + Widget build(context) { + + // Instantiate your class using Get.put() to make it available for all "child" routes there. + final Controller c = Get.put(Controller()); + + return Scaffold( + // Use Obx(()=> to update Text() whenever count is changed. + appBar: AppBar(title: Obx(() => Text("Clicks: ${c.count}"))), + + // Replace the 8 lines Navigator.push by a simple Get.to(). You don't need context + body: Center(child: ElevatedButton( + child: Text("Go to Other"), onPressed: () => Get.to(Other()))), + floatingActionButton: + FloatingActionButton(child: Icon(Icons.add), onPressed: c.increment)); + } +} + +class Other extends StatelessWidget { + // You can ask Get to find a Controller that is being used by another page and redirect you to it. + final Controller c = Get.find(); + + @override + Widget build(context){ + // Access the updated count variable + return Scaffold(body: Center(child: Text("${c.count}"))); + } +} +``` + +Résultat: + +![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/counter-app-gif.gif) + +Il s'agit d'un projet simple, mais il montre déjà clairement à quel point Get est puissant. Au fur et à mesure que votre projet se développe, cette différence deviendra plus importante. + +Get a été conçu pour travailler avec des équipes, mais cela simplifie le travail d'un développeur individuel. + +Améliorez vos délais, livrez tout à temps sans perdre vos performances. Get n'est pas pour tout le monde, mais si vous avez identifié avec cette phrase, Get est pour vous! diff --git a/docs/i18n/fr/docusaurus-plugin-content-docs/current/pillars/_category_.json b/docs/i18n/fr/docusaurus-plugin-content-docs/current/pillars/_category_.json new file mode 100644 index 000000000..22302abfd --- /dev/null +++ b/docs/i18n/fr/docusaurus-plugin-content-docs/current/pillars/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "Les 3 piliers", + "position": 3, + "link": { + "type": "index-généré", + "description": "Les 3 piliers de GetX." + } +} diff --git a/docs/i18n/fr/docusaurus-plugin-content-docs/current/pillars/dependency-management.md b/docs/i18n/fr/docusaurus-plugin-content-docs/current/pillars/dependency-management.md new file mode 100644 index 000000000..25311e5cc --- /dev/null +++ b/docs/i18n/fr/docusaurus-plugin-content-docs/current/pillars/dependency-management.md @@ -0,0 +1,404 @@ +--- +sidebar_position: 3 +--- + +# Dépendance + +Get a un gestionnaire de dépendances simple et puissant qui vous permet de récupérer la même classe que votre Bloc ou contrôleur avec seulement 1 ligne de code, pas de contexte de fournisseur, pas de Widget hérité : + +```dart +Controller controller = Get.put(Controller()); // Rather Controller controller = Controller(); +``` + +Au lieu d'instancier votre classe dans la classe que vous utilisez, vous l'instanciez dans l'instance Get qui le rendra disponible dans votre application. +Vous pouvez donc utiliser votre contrôleur (ou classe Bloc) normalement + +- Remarque : Si vous utilisez Get's State Manager, prêtez plus d'attention à l'API [Bindings](#bindings), qui facilitera la connexion de votre vue à votre contrôleur. +- Note2: Obtenir la gestion des dépendances est décloué à partir d'autres parties du paquet, donc si par exemple votre application utilise déjà un gestionnaire d'état (n'importe qui, n'importe quel, cela n'a aucune importance), vous n'avez pas besoin de changer cela, vous pouvez utiliser ce gestionnaire d'injection de dépendances sans aucun problème + +## Méthodes d'instanciation + +Les méthodes et ses paramètres configurables sont : + +### Get.put() + +La façon la plus courante d'insérer une dépendance. Bon pour les contrôleurs de vos points de vue, par exemple. + +```dart +Get.put(SomeClass()); +Get.put(LoginController(), permanent: true); +Get.put(ListItemController, tag: "some unique string"); +``` + +Ceci est toutes les options que vous pouvez définir lors de l'utilisation de put: + +```dart +Get.put( + // mandatory: the class that you want to get to save, like a controller or anything + // note: "S" means that it can be a class of any type + S dependency + + // optional: this is for when you want multiple classess that are of the same type + // since you normally get a class by using Get.find(), + // you need to use tag to tell which instance you need + // must be unique string + String tag, + + // optional: by default, get will dispose instances after they are not used anymore (example, + // the controller of a view that is closed), but you might need that the instance + // to be kept there throughout the entire app, like an instance of sharedPreferences or something + // so you use this + // defaults to false + bool permanent = false, + + // optional: allows you after using an abstract class in a test, replace it with another one and follow the test. + // defaults to false + bool overrideAbstract = false, + + // optional: allows you to create the dependency using function instead of the dependency itself. + // this one is not commonly used + InstanceBuilderCallback builder, +) +``` + +### Get.lazyPut + +Il est possible de lazyLoad une dépendance pour qu'elle ne soit instanciée que lorsqu'elle est utilisée. Très utile pour les classes coûteuses de calcul ou si vous voulez instancier plusieurs classes en un seul endroit (comme dans une classe de liaisons) et vous savez que vous n'allez pas utiliser cette classe à ce moment-là. + +```dart +/// ApiMock will only be called when someone uses Get.find for the first time +Get.lazyPut(() => ApiMock()); + +Get.lazyPut( + () { + // ... some logic if needed + return FirebaseAuth(); + }, + tag: Math.random().toString(), + fenix: true +) + +Get.lazyPut( () => Controller() ) +``` + +Ceci est toutes les options que vous pouvez définir lors de l'utilisation de lazyPut: + +```dart +Get.lazyPut( + // mandatory: a method that will be executed when your class is called for the first time + InstanceBuilderCallback builder, + + // optional: same as Get.put(), it is used for when you want multiple different instance of a same class + // must be unique + String tag, + + // optional: It is similar to "permanent", the difference is that the instance is discarded when + // is not being used, but when it's use is needed again, Get will recreate the instance + // just the same as "SmartManagement.keepFactory" in the bindings api + // defaults to false + bool fenix = false + +) +``` + +### Get.putAsync + +Si vous voulez enregistrer une instance asynchrone, vous pouvez utiliser `Get.putAsync`: + +```dart +Get.putAsync(() async { + final prefs = await SharedPreferences.getInstance(); + await prefs.setInt('counter', 12345); + return prefs; +}); + +Get.putAsync( () async => await YourAsyncClass() ) +``` + +Ceci est toutes les options que vous pouvez définir en utilisant putAsync: + +```dart +Get.putAsync( + + // mandatory: an async method that will be executed to instantiate your class + AsyncInstanceBuilderCallback builder, + + // optional: same as Get.put(), it is used for when you want multiple different instance of a same class + // must be unique + String tag, + + // optional: same as in Get.put(), used when you need to maintain that instance alive in the entire app + // defaults to false + bool permanent = false +) +``` + +### Get.create + +Celui-ci est délicat. Une explication détaillée de ce qu'est et des différences entre les autres peut être trouvée dans la section [Différences entre les méthodes :](#differences-entre-méthodes) + +```dart +Get.Create(() => SomeClass()); +Get.Create(() => LoginController()); +``` + +Ceci est toutes les options que vous pouvez définir lors de l'utilisation de la création : + +```dart +Get.create( + // required: a function that returns a class that will be "fabricated" every + // time `Get.find()` is called + // Example: Get.create(() => YourClass()) + FcBuilderFunc builder, + + // optional: just like Get.put(), but it is used when you need multiple instances + // of a of a same class + // Useful in case you have a list that each item need it's own controller + // needs to be a unique string. Just change from tag to name + String name, + + // optional: just like int`Get.put()`, it is for when you need to keep the + // instance alive thoughout the entire app. The difference is in Get.create + // permanent is true by default + bool permanent = true +``` + +## Utilisation de méthodes et de classes instanciées + +Imaginez que vous ayez parcouru de nombreux itinéraires, et que vous ayez besoin de données laissées derrière vous dans votre contrôleur, vous auriez besoin d'un gestionnaire d'état combiné avec le Provider ou Get\_it, correct ? Pas avec Get. Il vous suffit de demander à Get to "find" pour votre contrôleur, vous n'avez pas besoin de dépendances supplémentaires : + +```dart +final controller = Get.find(); +// OR +Controller controller = Get.find(); + +// 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. +``` + +Et puis vous serez en mesure de récupérer les données de votre contrôleur qui y ont été obtenues : + +```dart +Text(controller.textFromApi); +``` + +Puisque la valeur retournée est une classe normale, vous pouvez faire tout ce que vous voulez: + +```dart +int count = Get.find().getInt('counter'); +print(count); // out: 12345 +``` + +Pour supprimer une instance de Get: + +```dart +Get.delete(); //usually you don't need to do this because GetX already delete unused controllers +``` + +## Spécifier une instance alternative + +Une instance actuellement insérée peut être remplacée par une instance de classe similaire ou étendue en utilisant la méthode `replace` ou `lazyReplace`. Cela peut ensuite être récupéré en utilisant la classe originale. + +```dart +abstract class BaseClass {} +class ParentClass extends BaseClass {} + +class ChildClass extends ParentClass { + bool isChild = true; +} + + +Get.put(ParentClass()); + +Get.replace(ChildClass()); + +final instance = Get.find(); +print(instance is ChildClass); //true + + +class OtherClass extends BaseClass {} +Get.lazyReplace(() => OtherClass()); + +final instance = Get.find(); +print(instance is ChildClass); // false +print(instance is OtherClass); //true +``` + +## Différences entre les méthodes + +Tout d'abord, nous allons du `fenix` de Get.lazyPut et du `permanent` des autres méthodes. + +La différence fondamentale entre `permanent` et `fenix` est la façon dont vous voulez stocker vos instances. + +Renforcement : par défaut, GetX supprime les instances quand elles ne sont pas utilisées. +Cela signifie que : si l'écran 1 a un contrôleur 1 et que l'écran 2 a un contrôleur 2 et que vous retirez la première route de la pile, (comme si vous utilisez `Get. ff()` ou `Get.offNamed()`) le contrôleur 1 a perdu son utilisation, donc il sera effacé. + +Mais si vous voulez utiliser `permanent:true`, alors le contrôleur ne sera pas perdu dans cette transition - ce qui est très utile pour les services que vous voulez garder en vie tout au long de l'application. + +`fenix` dans l'autre main est pour les services que vous ne vous inquiétez pas de perdre entre les changements d'écran, mais quand vous avez besoin de ce service, vous vous attendez à ce qu'il soit vivant. Donc, en gros, il va disposer le contrôleur, service/classe inutilisé, mais quand vous en avez besoin, il "recréera à partir des cendres" une nouvelle instance. + +Procéder avec les différences entre les méthodes : + +- Get.put et Get. utAsync suit le même ordre de création, avec la différence que la seconde utilise une méthode asynchrone : ces deux méthodes créent et initialisent l'instance. Celui-ci est inséré directement dans la mémoire, en utilisant la méthode interne `insert` avec les paramètres `permanent: false` et `isSingleton: true` (ce paramètre isSingleton seul a pour but de dire si c'est d'utiliser la dépendance sur `dependency` ou s'il est d'utiliser la dépendance sur `FcBuilderFunc`). Après cela, `Get.find()` est appelé qui initialise immédiatement les instances qui sont en mémoire. + +- Get.create: Comme le nom l'indique, il va "créer" votre dépendance! Similaire à `Get.put()`, il appelle également la méthode interne `insert` pour l'instance. Mais `permanent` est devenu vrai et `isSingleton` est devenu faux (puisque nous "créon" notre dépendance, il n'y a aucun moyen pour que ce soit une instance de singleton, c'est pourquoi c'est faux). Et parce qu'il a `permanent: true`, nous avons par défaut l'avantage de ne pas le perdre entre les écrans ! Aussi, `Get.find()` n'est pas appelé immédiatement, il attend d'être utilisé dans l'écran pour être appelé. Il est créé de cette façon pour utiliser le paramètre `permanent`, depuis lors, il vaut la peine de le remarquer, `Get. reate()` a été fait avec le but de créer des instances non partagées, mais ne pas être disposé, comme par exemple un bouton dans une listView, que vous voulez une instance unique pour cette liste - à cause de cela, Get. reate doit être utilisé avec GetWidget. + +- Get.lazyPut: Comme le nom l'indique, c'est un processus paresseux. L'instance est créée, mais elle n'est pas appelée à être utilisée immédiatement, elle reste en attente d'être appelée. Contrairement aux autres méthodes, `insert` n'est pas appelé ici. À la place, l'instance est insérée dans une autre partie de la mémoire, une partie responsable de savoir si l'instance peut être recréée ou non, appelons-la "usine". Si nous voulons créer quelque chose à utiliser plus tard, il ne sera pas mélangé avec les choses qui ont été utilisées pour le moment. Et voici où la magie `fenix` entre : si vous choisissez de quitter `fenix: false`, et que votre `smartManagement` ne sont pas `keepFactory`, alors lorsque vous utilisez `Get. ind` l'instance changera la place dans la mémoire de l'"usine" à la zone de mémoire commune de l'instance. Juste après, par défaut, il est retiré de l'"usine". Maintenant, si vous choisissez `fenix: true`, l'instance continue d'exister dans cette partie dédiée, même en allant dans l'espace commun, pour être appelé à nouveau à l'avenir. + +## Liens + +Un des grands différentiels de ce paquet, peut-être, est la possibilité d'une intégration complète des routes, du gestionnaire d'état et du gestionnaire de dépendances. +Lorsqu'une route est retirée de la pile, tous les contrôleurs, toutes les variables et les instances d'objets qui y sont liés sont retirés de la mémoire. Si vous utilisez des flux ou des chronomètres, ils seront fermés automatiquement, et vous n'avez pas à vous inquiéter à ce sujet. +Dans la version 2.10 Obtenir complètement implémenté l'API Bindings. +Maintenant vous n'avez plus besoin d'utiliser la méthode d'initialisation. Vous n'avez même pas à taper vos contrôleurs si vous ne le voulez pas. Vous pouvez démarrer vos contrôleurs et vos services à l'endroit approprié pour cela. +La classe Binding est une classe qui découplera l'injection de dépendance, tout en "liant" les routes vers le gestionnaire d'état et le gestionnaire de dépendances. +Cela permet de savoir quel écran est affiché quand un contrôleur particulier est utilisé et de savoir où et comment s'en débarrasser. +De plus, la classe Binding vous permettra d'avoir un contrôle de configuration de SmartManager. Vous pouvez configurer les dépendances à organiser lors de la suppression d'une route de la pile, ou lorsque le widget qui l'a utilisé est mis en page, ni l'un ni l'autre. Vous aurez une gestion intelligente des dépendances qui fonctionne pour vous, mais malgré cela, vous pouvez le configurer comme vous le souhaitez. + +### Classe de liaisons + +- Créer une classe et implémenter la liaison + +```dart +class HomeBinding implements Bindings {} +``` + +Votre IDE vous demandera automatiquement d'outrepasser la méthode "dépendances", et il vous suffit de cliquer sur la lampe, outrepasser la méthode et insérer toutes les classes que vous allez utiliser sur cette route : + +```dart +class HomeBinding implements Bindings { + @override + void dependencies() { + Get.lazyPut(() => HomeController()); + Get.put(()=> Api()); + } +} + +class DetailsBinding implements Bindings { + @override + void dependencies() { + Get.lazyPut(() => DetailsController()); + } +} +``` + +Maintenant, il vous suffit d'informer votre itinéraire, que vous utiliserez cette liaison pour faire la connexion entre le gestionnaire de routes, les dépendances et les états. + +- Utilisation des routes nommées: + +```dart +getPages: [ + GetPage( + name: '/', + page: () => HomeView(), + binding: HomeBinding(), + ), + GetPage( + name: '/details', + page: () => DetailsView(), + binding: DetailsBinding(), + ), +]; +``` + +- Utiliser des itinéraires normaux : + +```dart +Get.to(Home(), binding: HomeBinding()); +Get.to(DetailsView(), binding: DetailsBinding()) +``` + +Là, vous n'avez plus à vous soucier de la gestion de la mémoire de votre application, Get will do it for vous. + +La classe de liaison est appelée lorsqu'une route est appelée, vous pouvez créer un "initialBinding dans votre GetMaterialApp pour insérer toutes les dépendances qui seront créées. + +```dart +GetMaterialApp( + initialBinding: SampleBind(), + home: Home(), +); +``` + +### Constructeur de liens + +La façon par défaut de créer une liaison est de créer une classe qui implémente Bindings. +Mais alternativement, vous pouvez utiliser le callback `BindingsBuilder` pour que vous puissiez simplement utiliser une fonction pour instancier ce que vous voulez. + +Exemple: + +```dart +getPages: [ + GetPage( + name: '/', + page: () => HomeView(), + binding: BindingsBuilder(() { + Get.lazyPut(() => ControllerX()); + Get.put(()=> Api()); + }), + ), + GetPage( + name: '/details', + page: () => DetailsView(), + binding: BindingsBuilder(() { + Get.lazyPut(() => DetailsController()); + }), + ), +]; +``` + +De cette façon, vous pouvez éviter de créer une classe de liaison pour chaque route, ce qui rend cela encore plus simple. + +Les deux façons de faire fonctionnent parfaitement bien et nous voulons que vous utilisiez ce qui convient le mieux à vos goûts. + +### Gestion intelligente + +GetX par défaut dispose des contrôleurs inutilisés de la mémoire, même si un échec se produit et qu'un widget qui l'utilise n'est pas correctement installé. +C'est ce que l'on appelle le mode `full` de gestion des dépendances. +Mais si vous voulez changer la façon dont GetX contrôle la disposition des classes, vous avez la classe `SmartManagement` que vous pouvez définir des comportements différents. + +#### Comment changer + +Si vous voulez modifier cette configuration (ce dont vous n'avez généralement pas besoin), c'est de cette façon : + +```dart +void main () { + runApp( + GetMaterialApp( + smartManagement: SmartManagement.onlyBuilder //here + home: Home(), + ) + ) +} +``` + +#### Complètement + +C'est celui par défaut. Éliminer les classes qui ne sont pas utilisées et qui n'ont pas été configurées pour être permanentes. Dans la plupart des cas, vous voudrez garder cette configuration intacte. Si vous débutez sur GetX, ne changez pas cela. + +#### Seulement le constructeur + +Avec cette option, seuls les contrôleurs démarrés dans `init:` ou chargés dans un Binding avec `Get.lazyPut()` seront jetés. + +Si vous utilisez `Get.put()` ou `Get.putAsync()` ou toute autre approche, SmartManagement n'aura pas les permissions d'exclure cette dépendance. + +Avec le comportement par défaut, même les widgets instanciés avec "Get.put" seront supprimés, contrairement à SmartManagement.onlyBuilder. + +#### Usine de gestion intelligente + +Tout comme SmartManagement.full, il supprimera ses dépendances lorsqu'il n'est plus utilisé. Cependant, il conservera leur usine, ce qui signifie qu'il recréera la dépendance si vous avez besoin de cette instance à nouveau. + +### Comment les liaisons fonctionnent sous la capuche + +Les liaisons créent des usines transitoires, qui sont créées dès que vous cliquez pour aller à un autre écran, et sera détruite dès que l'animation de changement d'écran aura lieu. +Cela arrive si vite que l'analyseur ne sera même pas en mesure de l'enregistrer. +Lorsque vous accédez à cet écran à nouveau, une nouvelle usine temporaire sera appelée, donc il est préférable d'utiliser SmartManagement. eepFactory, mais si vous ne voulez pas créer de Bindings, ou si vous voulez garder toutes vos dépendances sur la même Lie, cela vous aidera certainement. +Les usines prennent peu de mémoire, elles ne contiennent pas d'instances, mais une fonction avec la "forme" de cette classe que vous voulez. +Cela a un coût très bas en mémoire, mais puisque le but de cette lib est d'obtenir le maximum de performance possible en utilisant les ressources minimales, Obtenir des suppressions même les usines par défaut. +Utilisez ce qui vous convient le mieux. + +## Notes + +- NE PAS UTILISER SmartManagement.keepFactory si vous utilisez plusieurs Bindings. Il a été conçu pour être utilisé sans Liaison ou avec un seul Liage lié dans l'initialLiaison de GetMaterialApp. + +- L'utilisation de Bindings est complètement optionnelle, si vous le souhaitez, vous pouvez utiliser `Get.put()` et `Get.find()` sur les classes qui utilisent un contrôleur donné sans aucun problème. + Cependant, si vous travaillez avec Services ou toute autre abstraction, je vous recommande d'utiliser Bindings pour une meilleure organisation. diff --git a/docs/i18n/fr/docusaurus-plugin-content-docs/current/pillars/route-management.md b/docs/i18n/fr/docusaurus-plugin-content-docs/current/pillars/route-management.md new file mode 100644 index 000000000..846322af6 --- /dev/null +++ b/docs/i18n/fr/docusaurus-plugin-content-docs/current/pillars/route-management.md @@ -0,0 +1,560 @@ +--- +sidebar_position: 2 +--- + +# Itinéraire + +C'est l'explication complète de tout ce qu'il y a à Getx quand il s'agit de la gestion des routes. + +## Comment utiliser + +Ajouter ceci à votre fichier pubspec.yaml : + +```yaml +dependencies: + get: +``` + +Si vous utilisez des routes/snackbars/dialogs/bottomsheets sans contexte, ou utilisez les API de haut niveau, vous devez simplement ajouter "Get" avant votre MaterialApp, la transformer en GetMaterialApp et profiter ! + +```dart +GetMaterialApp( // Before: MaterialApp( + home: MyHome(), +) +``` + +## Navigation sans routes nommées + +Pour naviguer vers un nouvel écran : + +```dart +Get.to(NextScreen()); +``` + +Pour fermer les barres de collation, les dialogues, les feuilles du bas ou tout ce que vous fermeriez normalement avec Navigator.pop(contexte); + +```dart +Get.back(); +``` + +Pour passer à l'écran suivant et aucune option pour revenir à l'écran précédent (pour utiliser dans SplashScreens, les écrans de connexion et etc.) + +```dart +Get.off(NextScreen()); +``` + +Pour aller à l'écran suivant et annuler tous les itinéraires précédents (utiles dans les paniers, les sondages et les tests) + +```dart +Get.offAll(NextScreen()); +``` + +Pour naviguer vers l'itinéraire suivant, et recevoir ou mettre à jour les données dès que vous revenez depuis: + +```dart +var data = await Get.to(Payment()); +``` + +sur un autre écran, envoyer des données pour la route précédente : + +```dart +Get.back(result: 'success'); +``` + +Et utilisez: + +ex: + +```dart +if(data == 'success') madeAnything(); +``` + +Vous ne voulez pas apprendre notre syntaxe ? +Il suffit de changer le navigateur (majuscule) en navigateur (minuscule), et vous aurez toutes les fonctions de la navigation standard, sans avoir à utiliser le contexte +Exemple: + +```dart + +// Default Flutter navigator +Navigator.of(context).push( + context, + MaterialPageRoute( + builder: (BuildContext context) { + return HomePage(); + }, + ), +); + +// Get using Flutter syntax without needing context +navigator.push( + MaterialPageRoute( + builder: (_) { + return HomePage(); + }, + ), +); + +// Get syntax (It is much better, but you have the right to disagree) +Get.to(HomePage()); + + +``` + +## Navigation avec les routes nommées + +- Si vous préférez naviguer par namedRoutes, Get also supports ceci. + +Pour naviguer vers le prochain écran + +```dart +Get.toNamed("/NextScreen"); +``` + +Pour naviguer et supprimer l'écran précédent de l'arborescence. + +```dart +Get.offNamed("/NextScreen"); +``` + +Pour naviguer et supprimer tous les écrans précédents de l'arborescence. + +```dart +Get.offAllNamed("/NextScreen"); +``` + +Pour définir des routes, utilisez GetMaterialApp : + +```dart +void main() { + runApp( + GetMaterialApp( + initialRoute: '/', + getPages: [ + GetPage(name: '/', page: () => MyHomePage()), + GetPage(name: '/second', page: () => Second()), + GetPage( + name: '/third', + page: () => Third(), + transition: Transition.zoom + ), + ], + ) + ); +} +``` + +Pour gérer la navigation vers des routes non définies (404 erreur), vous pouvez définir une page unknownRoute dans GetMaterialApp. + +```dart +void main() { + runApp( + GetMaterialApp( + unknownRoute: GetPage(name: '/notfound', page: () => UnknownRoutePage()), + initialRoute: '/', + getPages: [ + GetPage(name: '/', page: () => MyHomePage()), + GetPage(name: '/second', page: () => Second()), + ], + ) + ); +} +``` + +### Envoyer des données aux Routes nommées + +Envoyez simplement ce que vous voulez pour des arguments. Obtenir n'importe quoi accepte ici, qu'il s'agisse d'une String, d'une Map, d'une Liste, ou même d'une instance de classe. + +```dart +Get.toNamed("/NextScreen", arguments: 'Get is the best'); +``` + +sur votre classe ou votre contrôleur : + +```dart +print(Get.arguments); +//print out: Get is the best +``` + +### Liens d'URL dynamiques + +Offrez des urls dynamiques avancés comme sur le Web. Les développeurs Web ont probablement déjà souhaité cette fonctionnalité sur Flutter, et très probablement ont vu un paquet promettre cette fonctionnalité et fournir une syntaxe totalement différente de celle qu'une URL aurait sur le web, mais Get aussi résout cela. + +```dart +Get.offAllNamed("/NextScreen?device=phone&id=354&name=Enzo"); +``` + +sur votre contrôleur/bloc/état/classe sans état: + +```dart +print(Get.parameters['id']); +// out: 354 +print(Get.parameters['name']); +// out: Enzo +``` + +Vous pouvez également recevoir des NamedParameters avec Get easily : + +```dart +void main() { + runApp( + GetMaterialApp( + initialRoute: '/', + getPages: [ + GetPage( + name: '/', + page: () => MyHomePage(), + ), + GetPage( + name: '/profile/', + page: () => MyProfile(), + ), + //You can define a different page for routes with arguments, and another without arguments, but for that you must use the slash '/' on the route that will not receive arguments as above. + GetPage( + name: '/profile/:user', + page: () => UserProfile(), + ), + GetPage( + name: '/third', + page: () => Third(), + transition: Transition.cupertino + ), + ], + ) + ); +} +``` + +Envoyer des données sur le nom de l'itinéraire + +```dart +Get.toNamed("/profile/34954"); +``` + +Sur le deuxième écran prendre les données par paramètre + +```dart +print(Get.parameters['user']); +// out: 34954 +``` + +ou envoyer plusieurs paramètres comme ceci + +```dart +Get.toNamed("/profile/34954?flag=true&country=italy"); +``` + +ou + +```dart +var parameters = {"flag": "true","country": "italy",}; +Get.toNamed("/profile/34954", parameters: parameters); +``` + +Sur le deuxième écran prendre les données par paramètres comme d'habitude + +```dart +print(Get.parameters['user']); +print(Get.parameters['flag']); +print(Get.parameters['country']); +// out: 34954 true italy +``` + +Et maintenant, tout ce que vous devez faire est d'utiliser Get. oNamed() pour naviguer sur vos routes nommées, sans aucun contexte (vous pouvez appeler vos routes directement depuis votre classe BLoC ou Controller), et lorsque votre application est compilée sur le web, vos routes apparaîtront dans l'url < 3 + +### Middleware + +Si vous voulez écouter Recevoir des événements pour déclencher des actions, vous pouvez utiliser routingCallback vers lui + +```dart +GetMaterialApp( + routingCallback: (routing) { + if(routing.current == '/second'){ + openAds(); + } + } +) +``` + +Si vous n'utilisez pas GetMaterialApp, vous pouvez utiliser l'API manuelle pour attacher un observateur Middleware. + +```dart +void main() { + runApp( + MaterialApp( + onGenerateRoute: Router.generateRoute, + initialRoute: "/", + navigatorKey: Get.key, + navigatorObservers: [ + GetObserver(MiddleWare.observer), // HERE !!! + ], + ), + ); +} +``` + +Créer une classe MiddleWare + +```dart +class MiddleWare { + static observer(Routing routing) { + /// You can listen in addition to the routes, the snackbars, dialogs and bottomsheets on each screen. + ///If you need to enter any of these 3 events directly here, + ///you must specify that the event is != Than you are trying to do. + if (routing.current == '/second' && !routing.isSnackbar) { + Get.snackbar("Hi", "You are on second route"); + } else if (routing.current =='/third'){ + print('last route called'); + } + } +} +``` + +Maintenant, utilisez Get on your code: + +```dart +class First extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + leading: IconButton( + icon: Icon(Icons.add), + onPressed: () { + Get.snackbar("hi", "i am a modern snackbar"); + }, + ), + title: Text('First Route'), + ), + body: Center( + child: ElevatedButton( + child: Text('Open route'), + onPressed: () { + Get.toNamed("/second"); + }, + ), + ), + ); + } +} + +class Second extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + leading: IconButton( + icon: Icon(Icons.add), + onPressed: () { + Get.snackbar("hi", "i am a modern snackbar"); + }, + ), + title: Text('second Route'), + ), + body: Center( + child: ElevatedButton( + child: Text('Open route'), + onPressed: () { + Get.toNamed("/third"); + }, + ), + ), + ); + } +} + +class Third extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text("Third Route"), + ), + body: Center( + child: ElevatedButton( + onPressed: () { + Get.back(); + }, + child: Text('Go back!'), + ), + ), + ); + } +} +``` + +## Navigation sans contexte + +### SnackBars + +Pour avoir un SnackBar simple avec Flutter, vous devez obtenir le contexte de l'échafaudage, ou vous devez utiliser une GlobalKey attachée à votre Échafaudage + +```dart +final snackBar = SnackBar( + content: Text('Hi!'), + action: SnackBarAction( + label: 'I am a old and ugly snackbar :(', + onPressed: (){} + ), +); +// Find the Scaffold in the widget tree and use +// it to show a SnackBar. +Scaffold.of(context).showSnackBar(snackBar); +``` + +Avec Get: + +```dart +Get.snackbar('Hi', 'i am a modern snackbar'); +``` + +Avec Get, tout ce que vous avez à faire est d'appeler votre Get.snackbar de n'importe où dans votre code ou de le personnaliser comme vous le souhaitez ! + +```dart +Get.snackbar( + "Hey i'm a Get SnackBar!", // title + "It's unbelievable! I'm using SnackBar without context, without boilerplate, without Scaffold, it is something truly amazing!", // message + icon: Icon(Icons.alarm), + shouldIconPulse: true, + onTap:(){}, + barBlur: 20, + isDismissible: true, + duration: Duration(seconds: 3), +); + + + ////////// ALL FEATURES ////////// + // Color colorText, + // Duration duration, + // SnackPosition snackPosition, + // Widget titleText, + // Widget messageText, + // bool instantInit, + // Widget icon, + // bool shouldIconPulse, + // double maxWidth, + // EdgeInsets margin, + // EdgeInsets padding, + // double borderRadius, + // Color borderColor, + // double borderWidth, + // Color backgroundColor, + // Color leftBarIndicatorColor, + // List boxShadows, + // Gradient backgroundGradient, + // TextButton mainButton, + // OnTap onTap, + // bool isDismissible, + // bool showProgressIndicator, + // AnimationController progressIndicatorController, + // Color progressIndicatorBackgroundColor, + // Animation progressIndicatorValueColor, + // SnackStyle snackStyle, + // Curve forwardAnimationCurve, + // Curve reverseAnimationCurve, + // Duration animationDuration, + // double barBlur, + // double overlayBlur, + // Color overlayColor, + // Form userInputForm + /////////////////////////////////// +``` + +Si vous préférez le snackbar traditionnel, ou si vous voulez le personnaliser à partir de zéro, y compris en ajoutant une seule ligne (Get. nackbar utilise un titre et un message obligatoires), vous pouvez utiliser +`Get.rawSnackbar();` qui fournit l'API RAW sur laquelle Get.snackbar a été construit. + +### Dialogues + +Pour ouvrir la boîte de dialogue : + +```dart +Get.dialog(YourDialogWidget()); +``` + +Pour ouvrir la boîte de dialogue par défaut : + +```dart +Get.defaultDialog( + onConfirm: () => print("Ok"), + middleText: "Dialog made in 3 lines of code" +); +``` + +Vous pouvez également utiliser Get.generalDialog au lieu de showGeneralDialog. + +Pour tous les autres widgets de dialogue Flut, y compris les cupertinos, vous pouvez utiliser Get.overlayContext au lieu du contexte, et l'ouvrir n'importe où dans votre code. +Pour les widgets qui n'utilisent pas Overlay, vous pouvez utiliser Get.context . +Ces deux contextes fonctionneront dans 99% des cas pour remplacer le contexte de votre interface utilisateur à l'exception des cas où le Widget hérité est utilisé sans contexte de navigation. + +### Feuilles en bas + +Get.bottomSheet est comme showModalBottomSheet, mais pas besoin de contexte. + +```dart +Get.bottomSheet( + Container( + child: Wrap( + children: [ + ListTile( + leading: Icon(Icons.music_note), + title: Text('Music'), + onTap: () {} + ), + ListTile( + leading: Icon(Icons.videocam), + title: Text('Video'), + onTap: () {}, + ), + ], + ), + ) +); +``` + +## Navigation imbriquée + +Rendez la navigation imbriquée de Flutter encore plus facile. +Vous n'avez pas besoin du contexte, et vous trouverez votre pile de navigation par Id. + +- REMARQUE : La création de piles de navigation parallèle peut être dangereuse. L'idéal n'est pas d'utiliser NestedNavigators ou d'utiliser avec modération. Si votre projet l'exige, allez-y, mais gardez à l'esprit que garder plusieurs piles de navigation en mémoire peut ne pas être une bonne idée pour la consommation de mémoire. + +Voyez à quel point c'est simple : + +```dart +Navigator( + key: Get.nestedKey(1), // create a key by index + initialRoute: '/', + onGenerateRoute: (settings) { + if (settings.name == '/') { + return GetPageRoute( + page: () => Scaffold( + appBar: AppBar( + title: Text("Main"), + ), + body: Center( + child: TextButton( + color: Colors.blue, + onPressed: () { + Get.toNamed('/second', id:1); // navigate by your nested route by index + }, + child: Text("Go to second"), + ), + ), + ), + ); + } else if (settings.name == '/second') { + return GetPageRoute( + page: () => Center( + child: Scaffold( + appBar: AppBar( + title: Text("Main"), + ), + body: Center( + child: Text("second") + ), + ), + ), + ); + } + } +), +``` diff --git a/docs/i18n/fr/docusaurus-plugin-content-docs/current/pillars/state-management.md b/docs/i18n/fr/docusaurus-plugin-content-docs/current/pillars/state-management.md new file mode 100644 index 000000000..c06083f01 --- /dev/null +++ b/docs/i18n/fr/docusaurus-plugin-content-docs/current/pillars/state-management.md @@ -0,0 +1,768 @@ +--- +sidebar_position: 1 +--- + +# État + +GetX n'utilise pas Streams ou ChangeNotifier comme d'autres gestionnaires d'état. Pourquoi? En plus de construire des applications pour android, iOS, web, fenêtres, macos et linux, Avec GetX, vous pouvez construire des applications serveur avec la même syntaxe que Flutter/GetX. Afin d'améliorer le temps de réponse et de réduire la consommation de RAM, nous avons créé GetValue et GetStream, qui sont des solutions de faible latence qui offrent beaucoup de performances, à un faible coût d'exploitation. Nous utilisons cette base pour construire toutes nos ressources, y compris la gestion de l'Etat. + +- _Complexity_: Certains gestionnaires d'état sont complexes et ont beaucoup de boilerplate. Avec GetX, vous n'avez pas à définir de classe pour chaque événement, le code est très propre et clair, et vous faites beaucoup plus en écrivant moins. De nombreuses personnes ont abandonné Flutter à cause de ce sujet et elles ont enfin une solution stupidement simple pour gérer les États. +- _Aucun générateur de code_: Vous passez la moitié de votre temps de développement à écrire votre logique d'application. Certains gestionnaires d'état comptent sur des générateurs de code pour avoir du code lisible au minimum. Changer une variable et avoir à exécuter build\_runner peut être improductif, et souvent le temps d'attente après un nettoyage flottant sera long, et vous devrez boire beaucoup de café. + +Avec GetX, tout est réactif, et rien ne dépend des générateurs de code, ce qui augmente votre productivité dans tous les aspects de votre développement. + +- \_Cela ne dépend pas du contexte : Vous avez probablement déjà besoin d'envoyer le contexte de votre vue à un contrôleur, faire le couplage de la vue avec la logique de votre entreprise. Vous avez probablement dû utiliser une dépendance pour un endroit sans contexte, et a dû passer le contexte à travers diverses classes et fonctions. Cela n'existe pas avec GetX. Vous avez accès à vos contrôleurs depuis vos contrôleurs sans contexte. Vous n'avez pas besoin d'envoyer le contexte par paramètre pour littéralement rien. +- _Contrôle granulaire_: la plupart des gestionnaires d'état sont basés sur ChangeNotifier. ChangeNotifier avertira tous les widgets qui dépendent de lui quand notifyListeners est appelé. Si vous avez 40 widgets sur un écran, qui ont une variable de votre classe ChangeNotifier, lorsque vous mettez à jour un, tous ces éléments seront reconstruits. + +Avec GetX, même les widgets imbriqués sont respectés. Si vous avez Obx surveillant votre ListView, et un autre surveillant une case à cocher dans la ListView, lorsque vous changez la valeur de la case à cocher, elle sera mise à jour lorsque vous changerez la valeur de la liste, seule la vue liste sera mise à jour. + +- \_Il ne se reconstruit que si sa variable change REALLY : GetX a un contrôle de flux, ce qui signifie que si vous affichez un texte avec 'Paola', si vous changez à nouveau la variable observable en 'Paola', le widget ne sera pas reconstruit. C'est parce que GetX sait que 'Paola' est déjà affiché dans le texte et ne fera pas de reconstructions inutiles. + +La plupart des gestionnaires d'état actuels seront reconstruits à l'écran. + +## Gestionnaire d'état réactif + +La programmation réactive peut aliéner de nombreuses personnes parce que l'on dit qu'elle est compliquée. GetX transforme la programmation réactive en quelque chose de assez simple : + +- Vous n'aurez pas besoin de créer des StreamControllers. +- Vous n'aurez pas besoin de créer un StreamBuilder pour chaque variable +- Vous n'aurez pas besoin de créer une classe pour chaque état. +- Vous n'aurez pas besoin de créer un get pour une valeur initiale. + +La programmation réactive avec Get est aussi simple que l'utilisation de setState. + +Imaginons que vous ayez une variable de nom et que chaque fois que vous la modifiez, tous les widgets qui l'utilisent sont automatiquement changés. + +Ceci est votre variable de compte: + +```dart +var name = 'Jonatas Borges'; +``` + +Pour le rendre observable, il vous suffit d'ajouter ".obs" à la fin de celui-ci : + +```dart +var name = 'Jonatas Borges'.obs; +``` + +C'est tout. C'est _que_ simple. + +À partir de maintenant, nous pourrions faire référence à ces variables réactive-".obs"(ervables) comme _Rx_. + +Qu'avons-nous fait sous le capot? Nous avons créé un `Stream` de `String`s, assigné la valeur initiale `"Jonatas Borges"` , nous avons notifié à tous les widgets qui utilisent `"Jonatas Borges"` qu'ils appartiennent maintenant à cette variable, et quand la valeur _Rx_ change, ils devront également changer. + +C'est la **magie de GetX**, grâce aux capacités de Dart. + +Mais, comme nous le savons, un `Widget` ne peut être modifié que s'il est à l'intérieur d'une fonction, parce que les classes statiques n'ont pas la puissance pour "auto-change". + +Vous devrez créer un `StreamBuilder` , vous abonner à cette variable pour écouter les modifications, et créez une "cascade" de `StreamBuilder` imbriqué si vous voulez changer plusieurs variables dans la même portée, n'est-ce pas? + +Non, vous n'avez pas besoin d'un `StreamBuilder` , mais vous avez raison sur les classes statiques. + +Eh bien, du point de vue, nous avons généralement beaucoup de boilerplate quand nous voulons changer un Widget spécifique, c'est la façon Flut. +Avec **GetX** vous pouvez également oublier ce code de la chaudière. + +`StreamBuilder( … )` ? `initialValue: …` ? `builder: …` ? Non, vous avez juste besoin de placer cette variable à l'intérieur d'un Widget `Obx()`. + +```dart +Obx (() => Text (controller.name)); +``` + +_De quoi avez-vous besoin pour mémoriser ?_ Seulement `Obx(() =>` . + +Vous passez juste ce Widget à travers une fonction de flèche dans un `Obx()` (le "Observateur" du _Rx_). + +`Obx` est assez intelligent, et ne changera que si la valeur de `controller.name` change. + +Si `name` est `"John"` , et que vous le changez en `"John"` ( `name. alue = "John"` ), comme c'est la même `valeur` qu'avant, rien ne changera à l'écran, et `Obx` , pour enregistrer des ressources, ignorera simplement la nouvelle valeur et ne reconstruira pas le Widget. **N'est-ce pas incroyable ?** + +> Alors, que se passe-t-il si j'ai 5 variables _Rx_ (observables) dans un `Obx` ? + +Cela ne fera que se mettre à jour quand **tout** d'entre eux changeront. + +> Et si j'ai 30 variables dans une classe, quand je mets à jour une classe, cela mettra-t-il à jour **toutes** les variables qui sont dans cette classe? + +Non, juste le **widget spécifique** qui utilise cette variable _Rx_. + +Donc **GetX** ne met à jour l'écran que lorsque la variable _Rx_ change sa valeur. + +``` + +final isOpen = false.obs; + +// NOTHING will happen... same value. +void onButtonTap() => isOpen.value=false; +``` + +### Avantages + +**GetX()** vous aide quand vous avez besoin d'un contrôle **granulaire** sur ce qui est mis à jour. + +Si vous n'avez pas besoin de `unique IDs`, car toutes vos variables seront modifiées lorsque vous effectuerez une action, alors utilisez `GetBuilder` , +parce qu'il s'agit d'une mise à jour d'état simple (en blocs, comme `setState()` ), faite en quelques lignes de code. +Il a été rendu simple, pour avoir le moins d'impact sur le processeur, et juste pour remplir un seul but (un _état_ reconstruit) et dépenser le minimum de ressources possible. + +Si vous avez besoin d'un gestionnaire d'État **puissant** , vous ne pouvez pas vous tromper avec **GetX**. + +Cela ne fonctionne pas avec des variables, mais **flows**, tout ce qu'il contient est `Streams` sous le capot. + +Vous pouvez utiliser _rxDart_ en conjonction avec elle, car tout est `Streams`, +vous pouvez écouter l'événement `event` de chaque variable "_Rx_", +parce que tout ce qu'il contient est `Streams`. + +Il s'agit littéralement d'une approche _BLoC_, plus facile que _MobX_, et sans générateurs de code ni décorations. +Tu peux transformer **n'importe quoi** en un _"Observable"_ avec juste un `.obs` . + +### Performance maximale : + +En plus d'avoir un algorithme intelligent pour les reconstructions minimales, **GetX** utilise des comparateurs +pour s'assurer que l'état a changé. + +Si vous rencontrez des erreurs dans votre application et que vous envoyez un changement d'état en double, +**GetX** s'assurera qu'il ne plantera pas. + +Avec **GetX** l'Etat ne change que si la `valeur` change. +C'est la différence principale entre **GetX** et l'utilisation de \_ `computed` de MobX\_. +En rejoignant deux **observables**, et un change; l'écouteur de cette _observable_ va également changer. + +Avec **GetX**, si vous rejoignez deux variables, `GetX()` (similaire à `Observer()` ) ne sera reconstruit que si cela implique un réel changement d'état. + +### Déclarer une variable réactive + +Vous avez 3 façons de transformer une variable en un "observable". + +1 - Le premier utilise **`Rx{Type}`**. + +```dart +// initial value is recommended, but not mandatory +final name = RxString(''); +final isLogged = RxBool(false); +final count = RxInt(0); +final balance = RxDouble(0.0); +final items = RxList([]); +final myMap = RxMap({}); +``` + +2 - La seconde est d'utiliser **`Rx`** et d'utiliser Darts Generics, `Rx` + +```dart +final name = Rx(''); +final isLogged = Rx(false); +final count = Rx(0); +final balance = Rx(0.0); +final number = Rx(0); +final items = Rx>([]); +final myMap = Rx>({}); + +// Custom classes - it can be any class, literally +final user = Rx(); +``` + +3 - La troisième approche, plus pratique, plus facile et préférée, ajoute juste **`.obs`** comme propriété de votre `valeur` : + +```dart +final name = ''.obs; +final isLogged = false.obs; +final count = 0.obs; +final balance = 0.0.obs; +final number = 0.obs; +final items = [].obs; +final myMap = {}.obs; + +// Custom classes - it can be any class, literally +final user = User().obs; +``` + +##### Avoir un état réactif est facile. + +Comme nous le savons, _Dart_ va maintenant vers _null safety_. +Pour être prêt, à partir de maintenant, vous devriez toujours commencer vos variables _Rx_ avec une **valeur initiale**. + +> Transformer une variable en _observable_ + _valeur initiale_ avec **GetX** est l'approche la plus simple et la plus pratique. + +Vous allez littéralement ajouter un « .obs» à la fin de votre variable, et **c'est cela**, vous l'avez rendu observable, +et son `. alue` , eh bien, sera la valeur _initiale_). + +### Utilisation des valeurs dans la vue + +```dart +// controller file +final count1 = 0.obs; +final count2 = 0.obs; +int get sum => count1.value + count2.value; +``` + +```dart +// view file +GetX( + builder: (controller) { + print("count 1 rebuild"); + return Text('${controller.count1.value}'); + }, +), +GetX( + builder: (controller) { + print("count 2 rebuild"); + return Text('${controller.count2.value}'); + }, +), +GetX( + builder: (controller) { + print("count 3 rebuild"); + return Text('${controller.sum}'); + }, +), +``` + +Si nous incrémentons `count1.value++` , cela affichera : + +- `count 1 reconstruction` + +- `count 3 rebuild` + +parce que `count1` a une valeur de `1` , et `1 + 0 = 1` , en changeant la valeur d'getter `sum`. + +Si nous changeons `count2.value++` , cela affichera : + +- `count 2 reconstruction` + +- `count 3 rebuild` + +parce que `count2.value` a changé, et le résultat de la `sum` est maintenant `2` . + +- NOTE: Par défaut, le tout premier événement reconstruira le widget, même s'il s'agit de la même `valeur`. + +Ce comportement existe à cause des variables booléennes. + +Imaginez que vous ayez fait ceci: + +```dart +var isLogged = false.obs; +``` + +Et puis, vous avez vérifié si un utilisateur est "connecté" pour déclencher un événement dans `ever` . + +```dart +@override +onInit() async { + ever(isLogged, fireRoute); + isLogged.value = await Preferences.hasToken(); +} + +fireRoute(logged) { + if (logged) { + Get.off(Home()); + } else { + Get.off(Login()); + } +} +``` + +Si `hasToken` était `false` , il n'y aurait aucun changement à `isLogged` , donc `ever()` ne serait jamais appelé. +Pour éviter ce type de comportement, le premier changement à un _observable_ déclenchera toujours un événement, +même s'il contient le même `. alue` . + +Tu peux supprimer ce comportement si tu veux, en utilisant +`isLogged.firstRebuild = false;` + +### Conditions à reconstruire + +De plus, Get fournit un contrôle étatique raffiné. Vous pouvez conditionner un événement (comme ajouter un objet à une liste), à une certaine condition. + +```dart +// First parameter: condition, must return true or false. +// Second parameter: the new value to apply if the condition is true. +list.addIf(item < limit, item); +``` + +Sans décorations, sans générateur de code, sans complications :smile: + +Connaissez-vous l'application Compteur de Flutter? Votre classe de contrôleur pourrait ressembler à ceci: + +```dart +class CountController extends GetxController { + final count = 0.obs; +} +``` + +Avec un simple : + +```dart +controller.count.value++ +``` + +Vous pouvez mettre à jour la variable compteur dans votre interface utilisateur, quel que soit l'endroit où elle est stockée. + +### Où les .obs peuvent être utilisés + +Vous pouvez transformer n'importe quoi sur les obs. Voici deux façons de le faire: + +- Vous pouvez convertir vos valeurs de classe en obs + +```dart +class RxUser { + final name = "Camila".obs; + final age = 18.obs; +} +``` + +- ou vous pouvez convertir la classe entière en étant observable + +```dart +class User { + User({String name, int age}); + var name; + var age; +} + +// when instantianting: +final user = User(name: "Camila", age: 18).obs; +``` + +### Note sur les listes + +Les listes sont complètement observables comme le sont les objets qui s'y trouvent. De cette façon, si vous ajoutez une valeur à une liste, elle reconstruira automatiquement les widgets qui l'utilisent. + +Vous n'avez pas non plus besoin d'utiliser ".value" avec des listes, l'étonnant api dart nous a permis de supprimer cela. +Les types primitifs malheureux tels que String et int ne peuvent pas être étendus, en utilisant . est obligatoire, mais ce ne sera pas un problème si vous travaillez avec des jeux et des setters pour ceux-ci. + +```dart +// On the controller +final String title = 'User Info:'.obs +final list = List().obs; + +// on the view +Text(controller.title.value), // String need to have .value in front of it +ListView.builder ( + itemCount: controller.list.length // lists don't need it +) +``` + +Lorsque vous rendez vos propres classes observables, il y a un autre moyen de les mettre à jour : + +```dart +// on the model file +// we are going to make the entire class observable instead of each attribute +class User() { + User({this.name = '', this.age = 0}); + String name; + int age; +} + +// on the controller file +final user = User().obs; +// when you need to update the user variable: +user.update( (user) { // this parameter is the class itself that you want to update +user.name = 'Jonny'; +user.age = 18; +}); +// an alternative way of update the user variable: +user(User(name: 'João', age: 35)); + +// on view: +Obx(()=> Text("Name ${user.value.name}: Age: ${user.value.age}")) +// you can also access the model values without the .value: +user().name; // notice that is the user variable, not the class (variable has lowercase u) +``` + +Vous n'avez pas à travailler avec des ensembles si vous ne le voulez pas. Vous pouvez utiliser l'api "assigner "et" assigné". +L'api "assigner" effacera votre liste et ajoutera un seul objet que vous voulez y commencer. +L'api "assignAll" effacera la liste existante et ajoutera tous les objets itérables que vous y injecterez. + +### Pourquoi je dois utiliser .value + +Nous pourrions supprimer l'obligation d'utiliser 'value' à `String` et `int` avec un simple générateur de décoration et de code, mais le but de cette bibliothèque est précisément d'éviter les dépendances externes. Nous voulons offrir un environnement prêt à la programmation, impliquant les éléments essentiels (gestion des routes, dépendances et états), d'une manière simple, légère et performante, sans avoir besoin d'un paquet externe. + +Vous pouvez littéralement ajouter 3 lettres à votre pubspec (recevoir) et un deux-points et commencer la programmation. Toutes les solutions incluses par défaut, de la gestion des itinéraires à la gestion des états, visent à faciliter la tâche, la productivité et la performance. + +Le poids total de cette bibliothèque est inférieur à celui d'un gestionnaire d'état unique, même si c'est une solution complète, et c'est ce que vous devez comprendre. + +Si vous êtes ennuyé par `. alue` , et comme un générateur de code, MobX est une excellente alternative, et vous pouvez l'utiliser en conjonction avec Get. Pour ceux qui veulent ajouter une dépendance unique dans pubspec et commencer à programmer sans se soucier de l'incompatibilité de la version d'un paquet avec un autre, ou si l'erreur d'une mise à jour d'état vient du gestionnaire d'état ou de la dépendance, ou encore, ne veulent pas s'inquiéter de la disponibilité des contrôleurs, si littéralement "juste la programmation", obtenir est tout simplement parfait. + +Si vous n'avez pas de problème avec le générateur de code MobX, ou si vous n'avez aucun problème avec le boilerplate BLoC, vous pouvez simplement utiliser Get pour les routes, et oublier qu'il a le gestionnaire d'état. Obtenir SEM et RSM sont nés par nécessité, mon entreprise avait un projet avec plus de 90 contrôleurs, et le générateur de code a simplement pris plus de 30 minutes pour terminer ses tâches après un Nettoyage Flutter sur une machine raisonnablement bonne. Si votre projet a 5, 10, 15 contrôleurs, tout gestionnaire d'état vous fournira bien. Si vous avez un projet ridiculement grand et que le générateur de code est un problème pour vous, vous avez reçu cette solution. + +Évidemment, si quelqu'un veut contribuer au projet et créer un générateur de code, ou quelque chose de similaire, je vais lier dans ce readme comme une alternative, mon besoin n'est pas le besoin pour tous les développeurs, mais pour l'instant je le dis, il ya de bonnes solutions qui font déjà cela, comme MobX. + +### Obx() + +Taper dans Get using Bindings n'est pas nécessaire. vous pouvez utiliser le widget Obx au lieu de GetX qui ne reçoit que la fonction anonyme qui crée un widget. +Évidemment, si vous n'utilisez pas de type, vous devrez avoir une instance de votre contrôleur pour utiliser les variables, ou utiliser `Get. liez()` .value ou Controller.to.value pour récupérer la valeur. + +### Collaborateurs-trices + +Les employés vous aideront à déclencher des callbacks spécifiques lorsqu'un événement se produit. + +```dart +/// Called every time `count1` changes. +ever(count1, (_) => print("$_ has been changed")); + +/// Called only first time the variable $_ is changed +once(count1, (_) => print("$_ was changed once")); + +/// Anti DDos - Called every time the user stops typing for 1 second, for example. +debounce(count1, (_) => print("debouce$_"), time: Duration(seconds: 1)); + +/// Ignore all changes within 1 second. +interval(count1, (_) => print("interval $_"), time: Duration(seconds: 1)); +``` + +Tous les travailleurs (sauf `debounce` ) ont un `condition` nommé paramètre, qui peut être un `bool` ou un callback qui renvoie un `bool`. +Cette `condition` définit quand la fonction `callback` s'exécute. + +Tous les travailleurs renvoient une instance `Worker`, que vous pouvez utiliser pour annuler ( via `dispose()` ) le travailleur. + +- **`jamais`** + +est appelée à chaque fois que la variable _Rx_ émet une nouvelle valeur. + +- **`toujours`** + +Comme `ever` , mais il prend une `List` de valeurs _Rx_ appelées chaque fois que sa variable est modifiée. Voilà. + +- **`une fois`** + +'once' n'est appelé que la première fois que la variable a été modifiée. + +- **`debounce`** + +'debounce' est très utile dans les fonctions de recherche, où vous voulez seulement que l'API soit appelée lorsque l'utilisateur a fini de taper. Si l'utilisateur saisit "Jonny", vous aurez 5 recherches dans les APIs, par la lettre J, o, n, n et y. Avec Get cela ne se produit pas, parce que vous aurez un Worker "debounce" qui ne sera déclenché qu'à la fin de la frappe. + +- **`intervalle`** + +'intervalle' est différent de la débouche. déviation si l'utilisateur fait 1000 changements à une variable en 1 seconde, il n'enverra que le dernier après le minuteur stipulé (ce qui est par défaut 800 millisecondes). L'intervalle ignorera à la place toutes les actions de l'utilisateur pour la période prévue. Si vous envoyez des événements pendant 1 minute, 1000 par seconde, le debounce ne vous enverra que le dernier, lorsque l'utilisateur arrête des événements errants. L'intervalle livrera des événements à chaque seconde, et s'il est réglé sur 3 secondes, il livrera 20 événements à la minute. Ceci est recommandé pour éviter les abus, dans les fonctions où l'utilisateur peut rapidement cliquer sur quelque chose et obtenir un avantage (imaginez que l'utilisateur peut gagner des pièces en cliquant sur quelque chose, s'il a cliqué 300 fois dans la même minute, il aurait 300 pièces, en utilisant l'intervalle, vous pouvez définir un calendrier pour 3 secondes, et même après avoir cliqué 300 ou mille fois le maximum qu'il obtiendrait en 1 minute serait 20 pièces, en cliquant 300 ou 1 million de fois). Le debounce est approprié pour les anti-DDos, pour les fonctions comme la recherche où chaque changement à onChange provoquerait une requête à votre api. Debounce attendra que l'utilisateur arrête de taper le nom, pour faire la demande. Si elle était utilisée dans le scénario de pièce mentionné ci-dessus, l'utilisateur ne gagnera que 1 pièce, parce qu'il n'est exécuté que lorsque l'utilisateur "pause" pour la durée établie. + +- REMARQUE : Les employés doivent toujours être utilisés lors du démarrage d'un contrôleur ou d'une classe, il devrait donc toujours être sur onInit (recommandé), constructeur de classe, ou l'initState d'un StatefulWidget (cette pratique n'est pas recommandée dans la plupart des cas, mais elle ne devrait pas avoir d'effets secondaires). + +## Gestionnaire d'état simple + +Get a un gestionnaire d'état qui est extrêmement léger et facile, qui n'utilise pas ChangeNotifier, répondra au besoin en particulier pour les nouveaux utilisateurs de Flutter, et ne posera pas de problèmes pour les applications de grande taille. + +GetBuilder vise précisément à contrôler plusieurs états. Imaginez que vous ayez ajouté 30 produits à un panier, vous cliquez sur supprimer un, en même temps que la liste est mise à jour, le prix est mis à jour et le badge dans le panier est mis à jour à un nombre plus petit. Ce type d'approche rend GetBuilder plus meurtrier, car il regroupe les états et les modifie tous à la fois sans aucune "logique de calcul" pour cela. GetBuilder a été créé en gardant à l'esprit ce type de situation, car pour un changement éphémère d'état, vous pouvez utiliser setState et vous n'aurez pas besoin d'un gestionnaire d'état pour cela. + +De cette façon, si vous voulez un contrôleur individuel, vous pouvez assigner des identifiants pour cela, ou utiliser GetX. C'est à vous de le faire, en vous rappelant que plus vous avez de widgets "individuels", plus les performances de GetX se démarqueront, alors que les performances de GetBuilder devraient être supérieures, quand il y a plusieurs changements d'état. + +### Avantages + +1. Mettre à jour uniquement les widgets requis. + +2. N'utilise pas changeNotifier, c'est le gestionnaire d'état qui utilise moins de mémoire (proche de 0mb). + +3. Oubliez StatefulWidget ! Avec Get vous n'en aurez jamais besoin. Avec les autres gestionnaires d'état, vous devrez probablement utiliser un StatefulWidget pour obtenir l'instance de votre fournisseur, BLoC, MobX Controller, etc. Mais avez-vous jamais cessé de penser que votre barre d'app, votre échafaudage et la plupart des widgets qui sont dans votre classe sont apatrides ? Alors pourquoi enregistrer l'état d'une classe entière, si vous ne pouvez enregistrer que l'état du Widget qui est état? Obtenez des solutions à ce problème aussi. Créez une classe sans état, rendez tout sans état. Si vous avez besoin de mettre à jour un seul composant, enveloppez-le avec GetBuilder, et son état sera maintenu. + +4. Organisez votre projet pour de vrais ! Les contrôleurs ne doivent pas être dans votre interface utilisateur, placer votre TextEditController, ou tout contrôleur que vous utilisez dans votre classe de contrôleur. + +5. Avez-vous besoin de déclencher un événement pour mettre à jour un widget dès qu'il est rendu ? GetBuilder a la propriété "initState", tout comme StatefulWidget, et vous pouvez appeler des événements de votre contrôleur, directement à partir de celui-ci, plus aucun événement n'est placé dans votre état d'initialisation. + +6. Avez-vous besoin de déclencher une action comme la fermeture des flux, des minuteurs et etc? GetBuilder dispose également de la propriété disposition, où vous pouvez appeler des événements dès que ce widget est détruit. + +7. Utiliser les flux uniquement si nécessaire. Vous pouvez utiliser vos StreamControllers à l'intérieur de votre contrôleur normalement, et utiliser StreamBuilder aussi normalement, mais n'oubliez pas, un flux consomme raisonnablement de la mémoire, la programmation réactive est belle, mais vous ne devriez pas abuser de cela. 30 flux ouverts simultanément peuvent être pires que changeNotifier (et changeNotifier est très mauvais). + +8. Mettre à jour les widgets sans dépenser de bélier pour cela. Obtenez les magasins uniquement l'ID de créateur de GetBuilder, et les mises à jour que GetBuilder si nécessaire. La consommation de mémoire du get ID dans la mémoire est très faible, même pour des milliers de GetBuilders. Lorsque vous créez un nouveau GetBuilder, vous partagez en fait l'état de GetBuilder qui a un ID de créateur. Un nouvel état n'est pas créé pour chaque GetBuilder, ce qui sauve un LOT DE RAM pour les applications de grande taille. Fondamentalement, votre demande sera entièrement sans état et les quelques Widgets qui seront Stateful (au sein de GetBuilder) auront un seul état, et donc la mise à jour d'un d'entre eux les mettra à jour tous. L'État n'en est qu'un seul. + +9. Obtenir est omniscient et dans la plupart des cas, il sait exactement le temps de retirer un contrôleur de la mémoire. Vous ne devriez pas vous inquiéter de savoir quand vous débarrasser d'un contrôleur, faites savoir le meilleur moment pour le faire. + +### Usage + +```dart +// Create controller class and extends GetxController +class Controller extends GetxController { + int counter = 0; + void increment() { + counter++; + update(); // use update() to update counter variable on UI when increment be called + } +} +// On your Stateless/Stateful class, use GetBuilder to update Text when increment be called +GetBuilder( + init: Controller(), // INIT IT ONLY THE FIRST TIME + builder: (_) => Text( + '${_.counter}', + ), +) +//Initialize your controller only the first time. The second time you are using ReBuilder for the same controller, do not use it again. Your controller will be automatically removed from memory as soon as the widget that marked it as 'init' is deployed. You don't have to worry about that, Get will do it automatically, just make sure you don't start the same controller twice. +``` + +**Terminé !** + +- Vous avez déjà appris comment gérer les états avec Get. + +- Note : Vous pouvez vouloir une organisation plus grande, et ne pas utiliser la propriété init. Pour cela, vous pouvez créer une classe et étendre la classe Binding et mentionner les contrôleurs qui seront créés dans cette route. Les contrôleurs ne seront pas créés à ce moment-là, au contraire, ce n'est qu'une déclaration, pour que la première fois que vous utilisez un contrôleur, Get sache où regarder. Obtenez restera pazyLoad et continuera à éliminer les contrôleurs quand ils ne sont plus nécessaires. Voyez l'exemple pub.dev pour voir comment ça fonctionne. + +Si vous naviguez sur de nombreuses routes et que vous avez besoin de données qui étaient dans votre contrôleur précédemment utilisé, il vous suffit d'utiliser GetBuilder à nouveau (sans init): + +```dart +class OtherClass extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + body: Center( + child: GetBuilder( + builder: (s) => Text('${s.counter}'), + ), + ), + ); + } + +``` + +Si vous avez besoin d'utiliser votre contrôleur à d'autres endroits, et en dehors de GetBuilder, il vous suffit de créer une entrée dans votre contrôleur et de l'avoir facilement. (ou utilisez `Get.find()` ) + +```dart +class Controller extends GetxController { + + /// You do not need that. I recommend using it just for ease of syntax. + /// with static method: Controller.to.increment(); + /// with no static method: Get.find().increment(); + /// There is no difference in performance, nor any side effect of using either syntax. Only one does not need the type, and the other the IDE will autocomplete it. + static Controller get to => Get.find(); // add this line + + int counter = 0; + void increment() { + counter++; + update(); + } +} +``` + +Et puis vous pouvez accéder directement à votre contrôleur, de cette façon : + +```dart +FloatingActionButton( + onPressed: () { + Controller.to.increment(), + } // This is incredibly simple! + child: Text("${Controller.to.counter}"), +), +``` + +Lorsque vous appuyez sur FloatingActionButton, tous les widgets qui écoutent la variable 'compteur' seront mis à jour automatiquement. + +### Comment gérer les contrôleurs + +Disons que nous avons ceci: + +`Classe a => Classe B (a le contrôleur X) => Classe C (a le contrôleur X)` + +Dans la classe A, le contrôleur n'est pas encore en mémoire, parce que vous ne l'avez pas encore utilisé (Get is lazyLoad). Dans la classe B, vous avez utilisé le contrôleur, et il est entré en mémoire. Dans la classe C, vous avez utilisé le même contrôleur que dans la classe B, Get partagera l'état du contrôleur B avec le contrôleur C, et le même contrôleur est toujours en mémoire. Si vous fermez l'écran C et l'écran B, Get prendra automatiquement le contrôleur X en mémoire et libérera des ressources. parce que la classe a n'utilise pas le contrôleur. Si vous repassez vers B, le contrôleur X entrera à nouveau dans la mémoire, si au lieu d'aller à la classe C, vous revenez à nouveau à la classe A, Get prendra le contrôleur en mémoire de la même manière. Si la classe C n'utilise pas le contrôleur, et que vous avez pris la classe B en mémoire, aucune classe n'utiliserait le contrôleur X et elle serait également déposée. La seule exception qui peut gâcher avec Get, est si vous retirez B de la route de manière inattendue et essayez d'utiliser le contrôleur en C. Dans ce cas, l'ID du créateur du contrôleur qui était en B a été supprimé, et Get a été programmé pour le retirer de la mémoire chaque contrôleur qui n'a pas d'ID de créateur. Si vous avez l'intention de le faire, ajoutez le flag "autoRemove: false" à GetBuilder de la classe B et utilisez adoptID = true; dans GetBuilder de la classe C. + +### Vous n'aurez plus besoin de StatefulWidgets + +Utiliser StatefulWidgets signifie stocker inutilement l'état des écrans entiers, même si vous avez besoin de reconstruire un widget, vous l'intégrerez dans un Consumer/Observer/BlocProvider/GetBuilder/GetX/Obx, qui sera un autre StatefulWidget. +La classe StatefulWidget est une classe plus grande que StatelessWidget, qui allouera plus de RAM, et cela peut ne pas faire une différence significative entre une ou deux classes, mais cela sera très certainement le cas quand vous en aurez 100 ! +À moins que vous n'ayez besoin d'utiliser un mixin, comme TickerProviderStateMixin, il sera totalement inutile d'utiliser un StatefulWidget avec Get. + +Vous pouvez appeler toutes les méthodes d'un StatefulWidget directement depuis un GetBuilder. +Si vous devez appeler la méthode initState() ou dispose() par exemple, vous pouvez les appeler directement ; + +```dart +GetBuilder( + initState: (_) => Controller.to.fetchApi(), + dispose: (_) => Controller.to.closeStreams(), + builder: (s) => Text('${s.username}'), +), +``` + +Une meilleure approche est d'utiliser la méthode onInit() et onClose() directement depuis votre contrôleur. + +```dart +@override +void onInit() { + fetchApi(); + super.onInit(); +} +``` + +- REMARQUE : Si vous voulez démarrer une méthode au moment où le contrôleur est appelé pour la première fois, Vous n'avez PAS BESOIN d'utiliser des constructeurs pour cela, en fait, en utilisant un paquet axé sur les performances comme Get, cette bordure sur les mauvaises pratiques, parce qu'il s'écarte de la logique dans laquelle les contrôleurs sont créés ou alloués (si vous créez une instance de ce contrôleur, le constructeur sera appelé immédiatement, vous allez remplir un contrôleur avant même qu'il soit utilisé, vous allouez de la mémoire sans qu'elle soit utilisée, ce qui nuit aux principes de cette bibliothèque). Les méthodes onInit() ; et onClose(); ont été créés pour cela, ils seront appelés lorsque le contrôleur sera créé, ou utilisé pour la première fois, selon que vous utilisez Get. azyPut ou non. Si vous voulez, par exemple, faire un appel à votre API pour remplir des données, vous pouvez oublier la méthode obsolète de initState/disposition, démarrez juste votre appel à l'api dans onInit, et si vous avez besoin d'exécuter une commande comme la fermeture des flux, utilisez la fonction onClose() pour cela. + +### Pourquoi il existe + +Le but de ce paquet est précisément de vous donner une solution complète pour la navigation des routes, la gestion des dépendances et des états, en utilisant les dépendances les moins possibles, avec un degré élevé de découplage. Faites appel à toutes les API de lutte de haut et de bas niveau pour vous assurer que vous travaillez avec le moins de couplage possible. Nous centralisons tout en un seul paquet, pour vous assurer que vous n'avez pas de couplage dans votre projet. De cette façon, vous ne pouvez mettre que des widgets dans votre vue, et laisser la partie de votre équipe qui fonctionne avec la logique d'entreprise librement, pour travailler avec la logique commerciale sans dépendre de tout élément de la vue. Cela fournit un environnement de travail beaucoup plus propre, de sorte qu'une partie de votre équipe ne fonctionne qu'avec des widgets, sans se soucier d'envoyer des données à votre contrôleur, et une partie de votre équipe ne travaille qu'avec la logique commerciale dans son ensemble, sans dépendre d'aucun élément de la vue. + +Donc pour simplifier ceci : +Vous n'avez pas besoin d'appeler des méthodes dans initState et de les envoyer par paramètre à votre contrôleur, ni utiliser le constructeur de votre contrôleur pour cela, vous avez la méthode onInit() qui est appelée au bon moment pour démarrer vos services. +Vous n'avez pas besoin d'appeler l'appareil, vous avez la méthode onClose() qui sera appelée au moment exact où votre contrôleur n'est plus nécessaire et sera retiré de la mémoire. De cette façon, laisser les vues pour les widgets seulement, s'abstenir de toute logique commerciale de cela. + +N'appelez pas une méthode d'élimination dans GetxController, il ne fera rien, n'oubliez pas que le contrôleur n'est pas un Widget, vous ne devriez pas le « disposer », et il sera automatiquement et intelligemment retiré de la mémoire par Get. Si vous avez utilisé un flux sur lui et que vous voulez le fermer, insérez-le dans la méthode fermée. Exemple: + +```dart +class Controller extends GetxController { + StreamController user = StreamController(); + StreamController name = StreamController(); + + /// close stream = onClose method, not dispose. + @override + void onClose() { + user.close(); + name.close(); + super.onClose(); + } +} +``` + +Cycle de vie du contrôleur : + +- onInit() où il est créé. +- onClose() où il est fermé pour effectuer des modifications dans la préparation de la méthode de suppression +- supprimé: vous n'avez pas accès à cette API car elle supprime littéralement le contrôleur de la mémoire. Elle est littéralement supprimée, sans laisser de trace. + +### Autres façons de l'utiliser + +Vous pouvez utiliser une instance de contrôleur directement sur la valeur de GetBuilder: + +```dart +GetBuilder( + init: Controller(), + builder: (value) => Text( + '${value.counter}', //here + ), +), +``` + +Vous pouvez également avoir besoin d'une instance de votre contrôleur en dehors de votre GetBuilder, et vous pouvez utiliser ces approches pour atteindre ceci: + +```dart +class Controller extends GetxController { + static Controller get to => Get.find(); +[...] +} +// on you view: +GetBuilder( + init: Controller(), // use it only first time on each controller + builder: (_) => Text( + '${Controller.to.counter}', //here + ) +), +``` + +ou + +```dart +class Controller extends GetxController { + // static Controller get to => Get.find(); // with no static get +[...] +} +// on stateful/stateless class +GetBuilder( + init: Controller(), // use it only first time on each controller + builder: (_) => Text( + '${Get.find().counter}', //here + ), +), +``` + +- Pour cela, vous pouvez utiliser des approches "non-canoniques". Si vous utilisez un autre gestionnaire de dépendances, comme get\_it, modulaire, etc., et que vous voulez simplement fournir l'instance du contrôleur, vous pouvez faire ceci : + +```dart +Controller controller = Controller(); +[...] +GetBuilder( + init: controller, //here + builder: (_) => Text( + '${controller.counter}', // here + ), +), + +``` + +### IDs uniques + +Si vous voulez affiner le contrôle de mise à jour d'un widget avec GetBuilder, vous pouvez leur assigner des ID uniques : + +```dart +GetBuilder( + id: 'text' + init: Controller(), // use it only first time on each controller + builder: (_) => Text( + '${Get.find().counter}', //here + ), +), +``` + +Et mettez à jour cette forme : + +```dart +update(['text']); +``` + +Vous pouvez également imposer des conditions pour la mise à jour : + +```dart +update(['text'], counter < 10); +``` + +GetX le fait automatiquement et ne reconstruit que le widget qui utilise la variable exacte qui a été modifiée, si vous changez une variable par la même valeur que la précédente, ce qui n'implique pas un changement d'état , GetX ne reconstruira pas le widget pour économiser de la mémoire et les cycles CPU (3 est affiché à l'écran). et vous changez à nouveau la variable à 3. Dans la plupart des gestionnaires d'état, cela provoquera une nouvelle reconstruction, mais avec GetX, le widget ne sera reconstruit que si en fait son état a changé). + +## Mélanger les deux gestionnaires d'état + +Certaines personnes ont ouvert une demande de fonctionnalité, car elles ne voulaient utiliser qu'un seul type de variable réactive, et les autres mécaniques, et avaient besoin d'insérer un Obx dans un GetBuilder pour cela. MixinBuilder a été créé pour y penser. Il permet à la fois des changements réactifs en modifiant des variables ".obs" et des mises à jour mécaniques via update(). Cependant, parmi les 4 widgets il est celui qui consomme le plus de ressources, car en plus d'avoir un abonnement pour recevoir des événements de changement de la part de ses enfants, il souscrit à la méthode de mise à jour de son contrôleur. + +L'extension de GetxController est importante, car ils ont des cycles de vie, et peuvent "démarrer" et "fin" les événements dans leurs méthodes onInit() et onClose() . Vous pouvez utiliser n'importe quelle classe pour cela, mais je vous recommande fortement d'utiliser la classe GetxController pour placer vos variables, qu'ils soient observables ou non. + +## Mixin + +Une autre façon de gérer votre état `UI` est d'utiliser le `StateMixin`. +Pour l'implémenter, utilisez le `with` pour ajouter le `StateMixin` +à votre contrôleur qui permet un modèle T. + +```dart +class Controller extends GetController with StateMixin{} +``` + +La méthode `change()` change l'état quand nous le voulons. +Il suffit de transmettre les données et le statut de cette façon : + +```dart +change(data, status: RxStatus.success()); +``` + +RxStatus autorise ces statuts : + +```dart +RxStatus.loading(); +RxStatus.success(); +RxStatus.empty(); +RxStatus.error('message'); +``` + +Pour le représenter dans l'interface utilisateur, utilisez : + +```dart +class OtherClass extends GetView { + @override + Widget build(BuildContext context) { + return Scaffold( + + body: controller.obx( + (state)=>Text(state.name), + + // here you can put your custom loading indicator, but + // by default would be Center(child:CircularProgressIndicator()) + onLoading: CustomLoadingIndicator(), + onEmpty: Text('No data found'), + + // here also you can set your own error widget, but by + // default will be an Center(child:Text(error)) + onError: (error)=>Text(error), + ), + ); +} +``` + +## GetBuilder vs GetX vs Obx vs MixinBuilder + +En une décennie de travail avec la programmation, j'ai pu apprendre des leçons précieuses. + +Mon premier contact avec la programmation réactive a été si "wow, c'est incroyable" et en fait la programmation réactive est incroyable. +Cependant, il ne convient pas à toutes les situations. Souvent, tout ce dont vous avez besoin est de changer l'état de 2 ou 3 widgets en même temps, ou un changement d'état éphémère, auquel cas la programmation réactive n'est pas mauvaise, mais elle n'est pas appropriée. + +La programmation réactive a une consommation de RAM plus élevée qui peut être compensée par le flux de travail individuel, qui s'assurera qu'un seul widget est reconstruit et si nécessaire, mais en créant une liste avec 80 objets, chacun avec plusieurs flux n'est pas une bonne idée. Ouvrez le dart inspecter et vérifiez combien un StreamBuilder consomme, et vous comprendrez ce que j'essaie de vous dire. + +C'est dans cet esprit que j'ai créé le simple gestionnaire d'État. C'est simple, et c'est exactement ce que vous devriez exiger: mettre à jour l'état en blocs d'une manière simple, et de la manière la plus économique. + +GetBuilder est très économique en RAM, et il y a à peine une approche plus économique que lui (au moins je ne peux pas en imaginer une, si elle existe, s'il vous plaît faites-le nous savoir). + +Cependant, GetBuilder est toujours un gestionnaire d'état mécanique, vous devez appeler update() comme vous devriez appeler la fonction Provider's notifyListeners(). + +Il y a d'autres situations où la programmation réactive est vraiment intéressante, et ne pas travailler avec elle, c'est la même chose que de réinventer la roue. Avec cela à l'esprit, GetX a été créé pour fournir tout ce qui est le plus moderne et le plus avancé dans un gestionnaire d'état. Il ne met à jour que ce qui est nécessaire et si nécessaire, si vous avez une erreur et envoyez 300 changements d'état en même temps, GetX filtrera et mettra à jour l'écran uniquement si l'état change réellement. + +GetX est encore plus économique que tout autre gestionnaire d'état réactif, mais il consomme un peu plus de RAM que GetBuilder. Penser à cela et viser à maximiser la consommation de ressources qu'Obx a été créé. Contrairement à GetX et GetBuilder, vous ne pourrez pas initialiser un contrôleur dans un Obx, c'est juste un Widget avec un StreamSubscription qui reçoit des événements de changement de vos enfants, c'est tout. Il est plus économique que GetX, mais perd pour GetBuilder, ce qui était à prévoir, car il est réactif, et GetBuilder a l'approche la plus simpliste qui existe, de stocker le hashcode d'un widget et son StateSetter. Avec Obx, vous n'avez pas besoin d'écrire votre type de contrôleur, et vous pouvez entendre le changement de plusieurs contrôleurs différents, mais il doit être initialisé avant, soit en utilisant l'approche d'exemple au début de ce readme, soit en utilisant la classe Bindings. diff --git a/docs/i18n/fr/docusaurus-plugin-content-docs/current/utils.md b/docs/i18n/fr/docusaurus-plugin-content-docs/current/utils.md new file mode 100644 index 000000000..f59bab4cf --- /dev/null +++ b/docs/i18n/fr/docusaurus-plugin-content-docs/current/utils.md @@ -0,0 +1,894 @@ +--- +sidebar_position: 4 +--- + +# Utils + +## Internationalisation + +### Traductions + +Les traductions sont conservées comme une simple carte de dictionnaire de valeur clé. +Pour ajouter des traductions personnalisées, créez une classe et étendez `Translations`. + +```dart +import 'package:get/get.dart'; + +class Messages extends Translations { + @override + Map> get keys => { + 'en_US': { + 'hello': 'Hello World', + }, + 'de_DE': { + 'hello': 'Hallo Welt', + } + }; +} +``` + +#### Utiliser les traductions + +Ajoute simplement `.tr` à la clé spécifiée et elle sera traduite, en utilisant la valeur actuelle de `Get.locale` et `Get.fallbackLocale`. + +```dart +Text('title'.tr); +``` + +#### Utilisation de la traduction au singulier et au pluriel + +```dart +var products = []; +Text('singularKey'.trPlural('pluralKey', products.length, Args)); +``` + +#### Utilisation de la traduction avec les paramètres + +```dart +import 'package:get/get.dart'; + + +Map> get keys => { + 'en_US': { + 'logged_in': 'logged in as @name with email @email', + }, + 'es_ES': { + 'logged_in': 'iniciado sesión como @name con e-mail @email', + } +}; + +Text('logged_in'.trParams({ + 'name': 'Jhon', + 'email': 'jhon@example.com' + })); +``` + +### Locales + +Passez les paramètres à `GetMaterialApp` pour définir la locale et les traductions. + +```dart +return GetMaterialApp( + translations: Messages(), // your translations + locale: Locale('en', 'US'), // translations will be displayed in that locale + fallbackLocale: Locale('en', 'UK'), // specify the fallback locale in case an invalid locale is selected. +); +``` + +#### Changer la locale + +Appelez `Get.updateLocale(locale)` pour mettre à jour la locale. Les traductions utilisent alors automatiquement la nouvelle locale. + +```dart +var locale = Locale('en', 'US'); +Get.updateLocale(locale); +``` + +#### Paramètres régionaux du système + +Pour lire la locale du système, vous pouvez utiliser `Get.deviceLocale`. + +```dart +return GetMaterialApp( + locale: Get.deviceLocale, +); +``` + +## Changer de thème + +Veuillez ne pas utiliser de widget de niveau supérieur à `GetMaterialApp` pour le mettre à jour. Cela peut déclencher des clés dupliquées. Beaucoup de gens sont habitués à l'approche préhistorique de la création d'un widget "Fournisseur de thèmes" simplement pour changer le thème de votre application, et ce n'est certainement PAS nécessaire avec **GetXTM**. + +Vous pouvez créer votre thème personnalisé et l'ajouter simplement dans `Get.changeTheme` sans aucune boilerplate pour cela: + +```dart +Get.changeTheme(ThemeData.light()); +``` + +Si vous voulez créer quelque chose comme un bouton qui change le thème dans `onTap`, vous pouvez combiner deux API **GetXTM** pour cela : + +- L'api qui vérifie si le sombre `Theme` est utilisé. +- Et le `Thème` Change API, vous pouvez juste le mettre dans un `onPressed`: + +```dart +Get.changeTheme(Get.isDarkMode? ThemeData.light(): ThemeData.dark()); +``` + +Quand `.darkmode` est activé, il bascule vers le thème \_light et quand le thème \_light devient actif, il passera à _dark theme_. + +## Se connecter + +GetConnect est un moyen facile de communiquer de votre dos à votre front avec http ou websockets + +### Configuration par défaut + +Vous pouvez simplement étendre GetConnect et utiliser les méthodes GET/POST/PUT/DELETE/SOCKET pour communiquer avec votre API Rest ou vos sockets. + +```dart +class UserProvider extends GetConnect { + // Get request + Future getUser(int id) => get('http://youapi/users/$id'); + // Post request + Future postUser(Map data) => post('http://youapi/users', body: data); + // Post request with File + Future> postCases(List image) { + final form = FormData({ + 'file': MultipartFile(image, filename: 'avatar.png'), + 'otherFile': MultipartFile(image, filename: 'cover.png'), + }); + return post('http://youapi/users/upload', form); + } + + GetSocket userMessages() { + return socket('https://yourapi/users/socket'); + } +} +``` + +### Configuration personnalisée + +GetConnect est hautement personnalisable. Vous pouvez définir l'URL de base, comme modificateur de réponse, comme modificateur de requêtes, définir un authentificateur et même le nombre de tentatives dans lesquelles il essaiera de s'authentifier, en plus de donner la possibilité de définir un décodeur standard qui transformera toutes vos requêtes en modèles sans configuration supplémentaire. + +```dart +class HomeProvider extends GetConnect { + @override + void onInit() { + // All request will pass to jsonEncode so CasesModel.fromJson() + httpClient.defaultDecoder = CasesModel.fromJson; + httpClient.baseUrl = 'https://api.covid19api.com'; + // baseUrl = 'https://api.covid19api.com'; // It define baseUrl to + // Http and websockets if used with no [httpClient] instance + + // It's will attach 'apikey' property on header from all requests + httpClient.addRequestModifier((request) { + request.headers['apikey'] = '12345678'; + return request; + }); + + // Even if the server sends data from the country "Brazil", + // it will never be displayed to users, because you remove + // that data from the response, even before the response is delivered + httpClient.addResponseModifier((request, response) { + CasesModel model = response.body; + if (model.countries.contains('Brazil')) { + model.countries.remove('Brazilll'); + } + }); + + httpClient.addAuthenticator((request) async { + final response = await get("http://yourapi/token"); + final token = response.body['token']; + // Set the header + request.headers['Authorization'] = "$token"; + return request; + }); + + //Autenticator will be called 3 times if HttpStatus is + //HttpStatus.unauthorized + httpClient.maxAuthRetries = 3; + } + + @override + Future> getCases(String path) => get(path); +} +``` + +## GetPage Middleware + +La GetPage a maintenant une nouvelle propriété qui prend une liste de GetMiddleWare et les exécute dans l'ordre spécifique. + +**Remarque** : lorsque GetPage a un Middlewares, tous les enfants de cette page auront automatiquement les mêmes marchandises du milieu. + +### Priorité + +L'ordre des Middlewares à exécuter peut être défini par la priorité dans le GetMiddleware. + +```dart +final middlewares = [ + GetMiddleware(priority: 2), + GetMiddleware(priority: 5), + GetMiddleware(priority: 4), + GetMiddleware(priority: -8), +]; +``` + +ces middlewares seront exécutés dans cet ordre **-8 => 2 => 4 => 5** + +### Rediriger + +Cette fonction sera appelée lorsque la page de la route appelée sera recherchée. Il prend les paramètres de route comme un résultat vers lequel rediriger. Ou donnez-lui null et il n'y aura pas de redirection. + +```dart +RouteSettings redirect(String route) { + final authService = Get.find(); + return authService.authed.value ? null : RouteSettings(name: '/login') +} +``` + +### sur la page appelée + +Cette fonction sera appelée lorsque cette page sera appelée avant tout ce qui est créé +vous pouvez l'utiliser pour changer quelque chose à propos de la page ou lui donner une nouvelle page + +```dart +GetPage onPageCalled(GetPage page) { + final authService = Get.find(); + return page.copyWith(title: 'Welcome ${authService.UserName}'); +} +``` + +### OnBindingsStart + +Cette fonction sera appelée juste avant l'initialisation de la liaison. +Ici, vous pouvez changer les Liens pour cette page. + +```dart +List onBindingsStart(List bindings) { + final authService = Get.find(); + if (authService.isAdmin) { + bindings.add(AdminBinding()); + } + return bindings; +} +``` + +### Démarrage de la construction sur la page + +Cette fonction sera appelée juste après l'initialisation des liaisons. +Ici, vous pouvez faire quelque chose après que vous avez créé les liaisons et avant de créer le widget de page. + +```dart +GetPageBuilder onPageBuildStart(GetPageBuilder page) { + print('bindings are ready'); + return page; +} +``` + +### OnPageBuilt + +Cette fonction sera appelée juste après que la fonction GetPage.page soit appelée et vous donnera le résultat de la fonction. et prendre le widget qui sera affiché. + +### Disposer de la page + +Cette fonction sera appelée juste après avoir éliminé tous les objets connexes (Contrôleurs, vues, ...) de la page. + +## Autres API Avancées + +```dart +// give the current args from currentScreen +Get.arguments + +// give name of previous route +Get.previousRoute + +// give the raw route to access for example, rawRoute.isFirst() +Get.rawRoute + +// give access to Routing API from GetObserver +Get.routing + +// check if snackbar is open +Get.isSnackbarOpen + +// check if dialog is open +Get.isDialogOpen + +// check if bottomsheet is open +Get.isBottomSheetOpen + +// remove one route. +Get.removeRoute() + +// back repeatedly until the predicate returns true. +Get.until() + +// go to next route and remove all the previous routes until the predicate returns true. +Get.offUntil() + +// go to next named route and remove all the previous routes until the predicate returns true. +Get.offNamedUntil() + +//Check in what platform the app is running +GetPlatform.isAndroid +GetPlatform.isIOS +GetPlatform.isMacOS +GetPlatform.isWindows +GetPlatform.isLinux +GetPlatform.isFuchsia + +//Check the device type +GetPlatform.isMobile +GetPlatform.isDesktop +//All platforms are supported independently in web! +//You can tell if you are running inside a browser +//on Windows, iOS, OSX, Android, etc. +GetPlatform.isWeb + + +// Equivalent to : MediaQuery.of(context).size.height, +// but immutable. +Get.height +Get.width + +// Gives the current context of the Navigator. +Get.context + +// Gives the context of the snackbar/dialog/bottomsheet in the foreground, anywhere in your code. +Get.contextOverlay + +// Note: the following methods are extensions on context. Since you +// have access to context in any place of your UI, you can use it anywhere in the UI code + +// If you need a changeable height/width (like Desktop or browser windows that can be scaled) you will need to use context. +context.width +context.height + +// Gives you the power to define half the screen, a third of it and so on. +// Useful for responsive applications. +// param dividedBy (double) optional - default: 1 +// param reducedBy (double) optional - default: 0 +context.heightTransformer() +context.widthTransformer() + +/// Similar to MediaQuery.sizeOf(context); +context.mediaQuerySize() + +/// Similar to MediaQuery.paddingOf(context); +context.mediaQueryPadding() + +/// Similar to MediaQuery.viewPaddingOf(context); +context.mediaQueryViewPadding() + +/// Similar to MediaQuery.viewInsetsOf(context); +context.mediaQueryViewInsets() + +/// Similar to MediaQuery.orientationOf(context); +context.orientation() + +/// Check if device is on landscape mode +context.isLandscape() + +/// Check if device is on portrait mode +context.isPortrait() + +/// Similar to MediaQuery.devicePixelRatioOf(context); +context.devicePixelRatio() + +/// Similar to MediaQuery.textScaleFactorOf(context); +context.textScaleFactor() + +/// Get the shortestSide from screen +context.mediaQueryShortestSide() + +/// True if width be larger than 800 +context.showNavbar() + +/// True if the shortestSide is smaller than 600p +context.isPhone() + +/// True if the shortestSide is largest than 600p +context.isSmallTablet() + +/// True if the shortestSide is largest than 720p +context.isLargeTablet() + +/// True if the current device is Tablet +context.isTablet() + +/// Returns a value according to the screen size +/// can give value for: +/// watch: if the shortestSide is smaller than 300 +/// mobile: if the shortestSide is smaller than 600 +/// tablet: if the shortestSide is smaller than 1200 +/// desktop: if width is largest than 1200 +context.responsiveValue() +``` + +### Paramètres globaux optionnels et configurations manuelles + +GetMaterialApp configure tout pour vous, mais si vous voulez configurer Get manuellement. + +```dart +MaterialApp( + navigatorKey: Get.key, + navigatorObservers: [GetObserver()], +); +``` + +Vous pourrez également utiliser votre propre Middleware dans `GetObserver`, cela n'influencera rien. + +```dart +MaterialApp( + navigatorKey: Get.key, + navigatorObservers: [ + GetObserver(MiddleWare.observer) // Here + ], +); +``` + +Vous pouvez créer _Paramètres globaux_ pour `Get`. Ajoute simplement `Get.config` à ton code avant d'envoyer n'importe quelle route. +Ou faites-le directement dans votre `GetMaterialApp` + +```dart +GetMaterialApp( + enableLog: true, + defaultTransition: Transition.fade, + opaqueRoute: Get.isOpaqueRouteDefault, + popGesture: Get.isPopGestureEnable, + transitionDuration: Get.defaultDurationTransition, + defaultGlobalState: Get.defaultGlobalState, +); + +Get.config( + enableLog = true, + defaultPopGesture = true, + defaultTransition = Transitions.cupertino +) +``` + +Vous pouvez optionnellement rediriger tous les messages de log de `Get`. +Si vous voulez utiliser votre propre paquet de journalisation favori, +et que vous voulez y capturer les logs : + +```dart +GetMaterialApp( + enableLog: true, + logWriterCallback: localLogWriter, +); + +void localLogWriter(String text, {bool isError = false}) { + // pass the message to your favourite logging package here + // please note that even if enableLog: false log messages will be pushed in this callback + // you get check the flag if you want through GetConfig.isLogEnable +} + +``` + +### Widgets d'état local + +Ces Widgets vous permettent de gérer une seule valeur et de garder l'état éphémère et localement. +Nous avons des saveurs pour la réactivité et la simplicité. +Par exemple, vous pouvez les utiliser pour activer/désactiver obscureText dans un `TextField`, peut-être créer un panneau +personnalisé, ou peut-être modifier l'index actuel dans `BottomNavigationBar` en changeant le contenu +du corps dans un `Scaffold`. + +#### Constructeur de valeur + +Une simplification de `StatefulWidget` qui fonctionne avec un callback `.setState` qui prend la valeur mise à jour. + +```dart +ValueBuilder( + initialValue: false, + builder: (value, updateFn) => Switch( + value: value, + onChanged: updateFn, // same signature! you could use ( newValue ) => updateFn( newValue ) + ), + // if you need to call something outside the builder method. + onUpdate: (value) => print("Value updated: $value"), + onDispose: () => print("Widget unmounted"), +), +``` + +#### ObxValue + +Similaire à [`ValueBuilder`](#valuebuilder), mais il s'agit de la version réactive, vous passez une instance Rx (souvenez-vous du .obs magique ?) et +se met à jour automatiquement... Ce n'est pas génial ? + +```dart +ObxValue((data) => Switch( + value: data.value, + onChanged: data, // Rx has a _callable_ function! You could use (flag) => data.value = flag, + ), + false.obs, +), +``` + +## Conseils utiles + +`.obs`ervables (aussi connu sous le nom de _Rx_ Types) ont une grande variété de méthodes et d'opérateurs internes. + +> Est très commun de _croire_ qu'une propriété avec `.obs` **IS** la valeur réelle... mais ne vous méprenez pas! +> Nous évitons la déclaration de type de la variable, car le compilateur de Dart est assez intelligent, et le code +> semble plus propre, mais: + +```dart +var message = 'Hello world'.obs; +print( 'Message "$message" has Type ${message.runtimeType}'); +``` + +Même si `message` _prints_ la valeur réelle de chaîne de caractères, le Type est **RxString**! + +Donc, vous ne pouvez pas faire `message.substring( 0, 4 )`. +Vous devez accéder à la vraie `value` à l'intérieur du _observable_: +La méthode la plus "utilisée" est `. alue`, mais saviez-vous que vous pouvez aussi utiliser... + +```dart +final name = 'GetX'.obs; +// only "updates" the stream, if the value is different from the current one. +name.value = 'Hey'; + +// All Rx properties are "callable" and returns the new value. +// but this approach does not accepts `null`, the UI will not rebuild. +name('Hello'); + +// is like a getter, prints 'Hello'. +name() ; + +/// numbers: + +final count = 0.obs; + +// You can use all non mutable operations from num primitives! +count + 1; + +// Watch out! this is only valid if `count` is not final, but var +count += 1; + +// You can also compare against values: +count > 2; + +/// booleans: + +final flag = false.obs; + +// switches the value between true/false +flag.toggle(); + + +/// all types: + +// Sets the `value` to null. +flag.nil(); + +// All toString(), toJson() operations are passed down to the `value` +print( count ); // calls `toString()` inside for RxInt + +final abc = [0,1,2].obs; +// Converts the value to a json Array, prints RxList +// Json is supported by all Rx types! +print('json: ${jsonEncode(abc)}, type: ${abc.runtimeType}'); + +// RxMap, RxList and RxSet are special Rx types, that extends their native types. +// but you can work with a List as a regular list, although is reactive! +abc.add(12); // pushes 12 to the list, and UPDATES the stream. +abc[3]; // like Lists, reads the index 3. + + +// equality works with the Rx and the value, but hashCode is always taken from the value +final number = 12.obs; +print( number == 12 ); // prints > true + +/// Custom Rx Models: + +// toJson(), toString() are deferred to the child, so you can implement override on them, and print() the observable directly. + +class User { + String name, last; + int age; + User({this.name, this.last, this.age}); + + @override + String toString() => '$name $last, $age years old'; +} + +final user = User(name: 'John', last: 'Doe', age: 33).obs; + +// `user` is "reactive", but the properties inside ARE NOT! +// So, if we change some variable inside of it... +user.value.name = 'Roi'; +// The widget will not rebuild!, +// `Rx` don't have any clue when you change something inside user. +// So, for custom classes, we need to manually "notify" the change. +user.refresh(); + +// or we can use the `update()` method! +user.update((value){ + value.name='Roi'; +}); + +print( user ); +``` + +## Mixin + +Une autre façon de gérer votre état `UI` est d'utiliser le `StateMixin`. +Pour l'implémenter, utilisez le `with` pour ajouter le `StateMixin` +à votre contrôleur qui permet un modèle T. + +```dart +class Controller extends GetController with StateMixin{} +``` + +La méthode `change()` change l'état quand nous le voulons. +Il suffit de transmettre les données et le statut de cette façon : + +```dart +change(data, status: RxStatus.success()); +``` + +RxStatus autorise ces statuts : + +```dart +RxStatus.loading(); +RxStatus.success(); +RxStatus.empty(); +RxStatus.error('message'); +``` + +Pour le représenter dans l'interface utilisateur, utilisez : + +```dart +class OtherClass extends GetView { + @override + Widget build(BuildContext context) { + return Scaffold( + + body: controller.obx( + (state)=>Text(state.name), + + // here you can put your custom loading indicator, but + // by default would be Center(child:CircularProgressIndicator()) + onLoading: CustomLoadingIndicator(), + onEmpty: Text('No data found'), + + // here also you can set your own error widget, but by + // default will be an Center(child:Text(error)) + onError: (error)=>Text(error), + ), + ); +} +``` + +#### GetView + +J'aime ce Widget, est si simple, mais si utile! + +Est un Widget `const Stateless` qui a un getter `controller` pour un `Controller` enregistré, c'est tout. + +```dart + class AwesomeController extends GetController { + final String title = 'My Awesome View'; + } + + // ALWAYS remember to pass the `Type` you used to register your controller! + class AwesomeView extends GetView { + @override + Widget build(BuildContext context) { + return Container( + padding: EdgeInsets.all(20), + child: Text(controller.title), // just call `controller.something` + ); + } + } +``` + +#### Obtenir la vue Responsive + +Étendre ce widget pour construire une vue responsive. +ce widget contient la propriété `screen` qui a toutes les informations +sur la taille et le type de l'écran. + +##### Comment l'utiliser + +Vous avez deux options pour le construire. + +- avec la méthode `builder` vous retournez le widget à construire. +- avec les méthodes `desktop`, `tablet`,`phone`, `watch`. la méthode + spécifique sera construite lorsque le type d'écran correspond à la méthode + quand l'écran est \[ScreenType.Tablet] la méthode `tablet` + sera expurgée, et ainsi de suite. + **Note:** Si vous utilisez cette méthode, veuillez définir la propriété `alwaysUseBuilder` à `false` + +Avec la propriété `settings` vous pouvez définir la limite de largeur pour les types d'écran. + +![example](https://github.com/SchabanBo/get_page_example/blob/master/docs/Example.gif?raw=true) +Code à cet écran +[code](https://github.com/SchabanBo/get_page_example/blob/master/lib/pages/responsive_example/responsive_view.dart) + +#### GetWidget + +La plupart des gens n'ont aucune idée de ce Widget, ou complètement confondre son utilisation. +Le cas d'utilisation est très rare, mais très spécifique: Il `caches` un Contrôleur. +À cause du _cache_, ne peut pas être un `const Stateless`. + +> Alors, quand avez-vous besoin de "cacher" un contrôleur ? + +Si vous utilisez, une autre fonctionnalité "pas si commune" de **GetX**: `Get.create()`. + +`Get.create(()=>Controller())` générera un nouveau `Controller` chaque fois que vous appelez +`Get.find()`, + +C'est là que réside `GetWidget`... comme vous pouvez l'utiliser, par exemple, +pour garder une liste des éléments de Todo. Donc, si le widget est reconstruit, il conservera la même instance de contrôleur. + +#### GetxService + +Cette classe est comme un `GetxController`, il partage le même cycle de vie ( `onInit()`, `onReady()`, `onClose()`). +Mais il n'y a pas de "logique" à l'intérieur. Il suffit de notifier **GetX** système d'injection de dépendance, que cette sous-classe +**ne peut pas** être retirée de la mémoire. + +Il est donc super utile de garder vos "Services" toujours joignables et actives avec `Get.find()`. J'aime: +`ApiService`, `StorageService`, `CacheService`. + +```dart +Future main() async { + await initServices(); /// AWAIT SERVICES INITIALIZATION. + runApp(SomeApp()); +} + +/// Is a smart move to make your Services intiialize before you run the Flutter app. +/// as you can control the execution flow (maybe you need to load some Theme configuration, +/// apiKey, language defined by the User... so load SettingService before running ApiService. +/// so GetMaterialApp() doesnt have to rebuild, and takes the values directly. +void initServices() async { + print('starting services ...'); + /// Here is where you put get_storage, hive, shared_pref initialization. + /// or moor connection, or whatever that's async. + await Get.putAsync(() => DbService().init()); + await Get.putAsync(SettingsService()).init(); + print('All services started...'); +} + +class DbService extends GetxService { + Future init() async { + print('$runtimeType delays 2 sec'); + await 2.delay(); + print('$runtimeType ready!'); + return this; + } +} + +class SettingsService extends GetxService { + void init() async { + print('$runtimeType delays 1 sec'); + await 1.delay(); + print('$runtimeType ready!'); + } +} + +``` + +La seule façon de supprimer un `GetxService`, est d'utiliser `Get.reset()` qui est comme un +"Hot Reboot" de votre application. So remember, if you need absolute persistence of a class instance during the +lifetime of your app, use `GetxService`. + +### Tests + +Vous pouvez tester vos contrôleurs comme n'importe quelle autre classe, y compris leur cycle de vie : + +```dart +class Controller extends GetxController { + @override + void onInit() { + super.onInit(); + //Change value to name2 + name.value = 'name2'; + } + + @override + void onClose() { + name.value = ''; + super.onClose(); + } + + final name = 'name1'.obs; + + void changeName() => name.value = 'name3'; +} + +void main() { + test(''' +Test the state of the reactive variable "name" across all of its lifecycles''', + () { + /// You can test the controller without the lifecycle, + /// but it's not recommended unless you're not using + /// GetX dependency injection + final controller = Controller(); + expect(controller.name.value, 'name1'); + + /// If you are using it, you can test everything, + /// including the state of the application after each lifecycle. + Get.put(controller); // onInit was called + expect(controller.name.value, 'name2'); + + /// Test your functions + controller.changeName(); + expect(controller.name.value, 'name3'); + + /// onClose was called + Get.delete(); + + expect(controller.name.value, ''); + }); +} +``` + +#### Conseils + +##### Mockito ou mocktail + +Si vous avez besoin de bouchonner votre GetxController/GetxService, vous devriez étendre GetxController, et le mélanger avec Mock, de cette façon + +```dart +class NotificationServiceMock extends GetxService with Mock implements NotificationService {} +``` + +##### Utiliser la fonction Get.reset() + +Si vous testez des widgets, ou des groupes de test, utilisez Get. à la fin de votre test ou dans tearDown pour réinitialiser tous les paramètres de votre test précédent. + +##### Get.testMode + +si vous utilisez votre navigation dans vos contrôleurs, utilisez `Get.testMode = true` au début de votre main. + +# Interruption des changements à partir de 2.0 + +1- Types Rx : + +| Avant | Après | +| -------------------- | ---------- | +| StringX | `RxString` | +| IntX | `RxInt` | +| MapX | `RxMap` | +| Liste X | `RxList` | +| Nombre de unnamed@@0 | `RxNum` | +| DoubleX | `RxDouble` | + +RxController et GetBuilder ont maintenant fusionné, vous n'avez plus besoin de mémoriser quel contrôleur vous voulez utiliser, il suffit d'utiliser GetxController, il fonctionnera pour une gestion simple de l'état et pour la réactive aussi. + +2- NamedRoutes +Avant: + +```dart +GetMaterialApp( + namedRoutes: { + '/': GetRoute(page: Home()), + } +) +``` + +Maintenant : + +```dart +GetMaterialApp( + getPages: [ + GetPage(name: '/', page: () => Home()), + ] +) +``` + +Pourquoi ce changement ? +Souvent, il peut être nécessaire de décider quelle page sera affichée à partir d'un paramètre, ou un jeton de connexion, l'approche précédente était inflexible, car elle ne l'autorisait pas. +L'insertion de la page dans une fonction a considérablement réduit la consommation de mémoire, car les routes ne seront pas allouées en mémoire depuis que l'application a été démarrée, et elle a également permis de faire ce type d'approche : + +```dart + +GetStorage box = GetStorage(); + +GetMaterialApp( + getPages: [ + GetPage(name: '/', page:(){ + return box.hasData('token') ? Home() : Login(); + }) + ] +) +``` diff --git a/docs/i18n/fr/docusaurus-theme-classic/navbar.json b/docs/i18n/fr/docusaurus-theme-classic/navbar.json new file mode 100644 index 000000000..ea8a237cf --- /dev/null +++ b/docs/i18n/fr/docusaurus-theme-classic/navbar.json @@ -0,0 +1,30 @@ +{ + "logo.alt": { + "message": "Logo du site", + "description": "The alt text of navbar logo" + }, + "item.label.Get Started": { + "message": "Commencer", + "description": "Navbar item with label Get Started" + }, + "item.label.About": { + "message": "À propos de", + "description": "Navbar item with label About" + }, + "item.label.Pillars": { + "message": "Piliers", + "description": "Navbar item with label Pillars" + }, + "item.label.Utils": { + "message": "Utils", + "description": "Navbar item with label Utils" + }, + "item.label.Community": { + "message": "Communauté", + "description": "Navbar item with label Community" + }, + "item.label.Concepts": { + "message": "Concepts", + "description": "Navbar item with label Concepts" + } +} diff --git a/docs/package.json b/docs/package.json new file mode 100644 index 000000000..798e73bb9 --- /dev/null +++ b/docs/package.json @@ -0,0 +1,51 @@ +{ + "name": "docs", + "version": "0.0.0", + "private": true, + "scripts": { + "docusaurus": "docusaurus", + "start": "docusaurus start", + "build": "docusaurus build", + "swizzle": "docusaurus swizzle", + "deploy": "docusaurus deploy", + "clear": "docusaurus clear", + "serve": "docusaurus serve", + "write-translations": "docusaurus write-translations", + "write-heading-ids": "docusaurus write-heading-ids", + "typecheck": "tsc", + "crowdin": "crowdin", + "crowdin:upload": "docusaurus write-translations && crowdin upload", + "crowdin:sync": "docusaurus write-translations && crowdin upload && crowdin download" + }, + "dependencies": { + "@docusaurus/core": "3.0.0", + "@docusaurus/preset-classic": "3.0.0", + "@mdx-js/react": "^3.0.0", + "clsx": "^1.2.1", + "prism-react-renderer": "^2.1.0", + "react": "^18.0.0", + "react-dom": "^18.0.0" + }, + "devDependencies": { + "@crowdin/cli": "^3.15.0", + "@docusaurus/module-type-aliases": "3.0.0", + "@docusaurus/tsconfig": "3.0.0", + "@docusaurus/types": "3.0.0", + "typescript": "~5.2.2" + }, + "browserslist": { + "production": [ + ">0.5%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 3 chrome version", + "last 3 firefox version", + "last 5 safari version" + ] + }, + "engines": { + "node": ">=18.0" + } +} diff --git a/docs/sidebars.ts b/docs/sidebars.ts new file mode 100644 index 000000000..acc7685ac --- /dev/null +++ b/docs/sidebars.ts @@ -0,0 +1,31 @@ +import type {SidebarsConfig} from '@docusaurus/plugin-content-docs'; + +/** + * Creating a sidebar enables you to: + - create an ordered group of docs + - render a sidebar for each doc of that group + - provide next/previous navigation + + The sidebars can be generated from the filesystem, or explicitly defined here. + + Create as many sidebars as you want. + */ +const sidebars: SidebarsConfig = { + // By default, Docusaurus generates a sidebar from the docs folder structure + tutorialSidebar: [{type: 'autogenerated', dirName: '.'}], + + // But you can create a sidebar manually + /* + tutorialSidebar: [ + 'intro', + 'hello', + { + type: 'category', + label: 'Tutorial', + items: ['tutorial-basics/create-a-document'], + }, + ], + */ +}; + +export default sidebars; diff --git a/docs/src/components/Banner/index.tsx b/docs/src/components/Banner/index.tsx new file mode 100644 index 000000000..fdb340be0 --- /dev/null +++ b/docs/src/components/Banner/index.tsx @@ -0,0 +1,43 @@ +import styles from "@site/src/pages/index.module.css"; +import Link from "@docusaurus/Link"; + +export default function () { + const Logo = require("@site/static/img/text.svg").default; + const Flutter = require("@site/static/img/flutter.svg").default; + + return ( +
+
+
+
+

+ is an + extra-light and powerful solution for + lutter +

+
+ State + Navigation + Dependencies +
+
+ + Get Started + +
+
+
+
+
+ ); +} diff --git a/docs/src/components/Banner/styles.module.css b/docs/src/components/Banner/styles.module.css new file mode 100644 index 000000000..0c9fbe609 --- /dev/null +++ b/docs/src/components/Banner/styles.module.css @@ -0,0 +1,61 @@ +/** + * CSS files with the .module.css suffix will be treated as CSS modules + * and scoped locally. + */ + +.heroBanner { + padding: 4rem 0; + text-align: center; + position: relative; + overflow: hidden; +} + +.heroText { + font-weight: 800; + max-width: 610px; + line-height: 1.1; + text-align: left; + font-size: 48px; +} + +.heroLeft { + margin-top: 250px; +} + +@media screen and (max-width: 996px) { + .heroBanner { + padding: 2rem; + } + + .heroLeft { + margin-top: 320px; + text-align: center; + } + + .heroText { + text-align: center; + font-size: 36px; + margin: 15px auto; + } +} + +.heroText svg { + display: inline-block !important; +} + +.heroText svg:first-child { + display: inline-block !important; + margin-bottom: -17px !important; + transform: rotateZ(359deg); +} + +.buttons { + display: flex; + align-items: center; + justify-content: center; +} + +.bg { + width: 100%; + height: 100vh; +} diff --git a/docs/src/components/CodeExample/index.tsx b/docs/src/components/CodeExample/index.tsx new file mode 100644 index 000000000..8bf79795d --- /dev/null +++ b/docs/src/components/CodeExample/index.tsx @@ -0,0 +1,10 @@ +export default function () { + return ( +
+

Flutter Made Easy

+
+ image code +
+
+ ); +} diff --git a/docs/src/components/Footer/index.tsx b/docs/src/components/Footer/index.tsx new file mode 100644 index 000000000..0f32714f9 --- /dev/null +++ b/docs/src/components/Footer/index.tsx @@ -0,0 +1,89 @@ +import Link from "@docusaurus/Link"; +import styles from "./styles.module.css"; + +export default function () { + const Logo = require("@site/static/img/text.svg").default; + + return ( +
+
+
+
+
+ + + +
+
+
+

Documentation

+
+
+ Get Started +
+
+ About +
+
+ Concepts +
+
+ Pillars +
+
+ Utils +
+
+
+

Community

+
+ + slack + + + + discord + + + + telegram + + + + github + +
+
+
+
+
+ GetX mantained by{" "} + jonataslaw, MIT + Licence. +
+
+
+ ); +} diff --git a/docs/src/components/Footer/styles.module.css b/docs/src/components/Footer/styles.module.css new file mode 100644 index 000000000..7d55caaa7 --- /dev/null +++ b/docs/src/components/Footer/styles.module.css @@ -0,0 +1,43 @@ +.copyright { + text-align: center; + padding: 8px; + color: #fff; + background: rgba(0, 0, 0, 0.69); +} + +.copyright a { + color: #fff !important; +} + +.heroText { + font-weight: 800; + max-width: 610px; + line-height: 1.1; + text-align: left; + font-size: 48px; +} + +@media screen and (max-width: 996px) { + .heroText { + text-align: center; + font-size: 36px; + margin: 15px auto; + } +} + +.heroText svg { + display: inline-block !important; +} + +.heroText svg:first-child { + display: inline-block !important; + margin-bottom: -17px !important; + transform: rotateZ(359deg); +} + +.footerInner { + display: flex; + justify-content: space-between; + flex-direction: column; + height: 100%; +} diff --git a/docs/src/components/HomepageFeatures/index.tsx b/docs/src/components/HomepageFeatures/index.tsx new file mode 100644 index 000000000..4aec943c7 --- /dev/null +++ b/docs/src/components/HomepageFeatures/index.tsx @@ -0,0 +1,78 @@ +import clsx from "clsx"; +import Heading from "@theme/Heading"; +import styles from "./styles.module.css"; + +type FeatureItem = { + title: string; + Svg: React.ComponentType>; + description: JSX.Element; +}; + +const FeatureList: FeatureItem[] = [ + { + title: "PERFORMANCE", + Svg: require("@site/static/img/rocket.svg").default, + description: ( + <> + GetX is focused on performance and minimum consumption of resources. + GetX does not use Streams or ChangeNotifier. + + ), + }, + { + title: "PRODUCTIVITY", + Svg: require("@site/static/img/productivity.svg").default, + description: ( + <> + GetX uses an easy and pleasant syntax. No matter what you want to do, + there is always an easier way with GetX. + + ), + }, + { + title: "ORGANIZATION", + Svg: require("@site/static/img/organization.svg").default, + description: ( + <> + GetX allows the total decoupling of the View, presentation logic, + business logic, dependency injection, and navigation. + + ), + }, +]; + +function Feature({ title, Svg, description }: FeatureItem) { + return ( +
+
+ +
+
+ {title} +

{description}

+
+
+ ); +} + +export default function HomepageFeatures(): JSX.Element { + return ( +
+
+
+
+

Principles

+
+
+
+ {FeatureList.map((props, idx) => ( + + ))} +
+
+
+ ); +} diff --git a/docs/src/components/HomepageFeatures/styles.module.css b/docs/src/components/HomepageFeatures/styles.module.css new file mode 100644 index 000000000..af3d3550b --- /dev/null +++ b/docs/src/components/HomepageFeatures/styles.module.css @@ -0,0 +1,11 @@ +.features { + display: flex; + align-items: center; + padding: 2rem 0; + width: 100%; +} + +.featureSvg { + height: 96px !important; + width: 64px; +} diff --git a/docs/src/css/custom.css b/docs/src/css/custom.css new file mode 100644 index 000000000..f10a086d2 --- /dev/null +++ b/docs/src/css/custom.css @@ -0,0 +1,129 @@ +/** + * Any CSS included here will be global. The classic template + * bundles Infima by default. Infima is a CSS framework designed to + * work well for content-centric websites. + */ + +/* You can override the default Infima variables here. */ +:root { + --ifm-color-primary: #8f2abb; + --ifm-color-primary-dark: #9b32c9; + --ifm-color-primary-darker: #8f2abb; + --ifm-color-primary-darkest: #9223c0; + --ifm-color-primary-light: #8e36b6; + --ifm-color-primary-lighter: #8f46b6; + --ifm-color-primary-lightest: #9e5fb4; + --ifm-code-font-size: 95%; + --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.1); +} + +/* For readability concerns, you should choose a lighter palette in dark mode. */ +[data-theme="dark"] { + --ifm-color-primary: #e2507d; + --ifm-color-primary-dark: #e2507d; + --ifm-color-primary-darker: #e2507d; + --ifm-color-primary-darkest: #e2507d; + --ifm-color-primary-light: #e2507d; + --ifm-color-primary-lighter: #e2507d; + --ifm-color-primary-lightest: #e2507d; + --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3); +} + +.container { + padding: 0 20px; + max-width: 1240px; +} + +.pill-text { + font-size: 1.3em; +} + +.pill { + display: inline-flex; + -webkit-appearance: none; + -moz-appearance: none; + -ms-appearance: none; + appearance: none; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -ms-flex-pack: center; + -webkit-justify-content: center; + justify-content: center; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + position: relative; + white-space: nowrap; + vertical-align: middle; + outline: 2px solid transparent; + outline-offset: 2px; + min-width: 60px; + height: 32px; + border-radius: 6px; + padding: 0 14px; + color: rgba(255, 94, 94, 0.87); + background-color: #ffe8e8; + -webkit-transition: 0.2s; + transition: 0.2s; + margin-right: 16px; + font-size: 12px; + line-height: 18px; + font-weight: 600; + box-shadow: 1px 2px 3px 0 #3333335e; +} + +.header-github-link:hover { + opacity: 0.6; +} + +.header-github-link:before { + background: url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'/%3E%3C/svg%3E") + no-repeat; + content: ""; + display: flex; + height: 24px; + width: 24px; +} + +[data-theme="dark"] .header-github-link::before { + background: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='white' d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'/%3E%3C/svg%3E") + no-repeat; +} + +.footer-container { + width: 100%; + height: 60vh; + padding-top: 125px; + margin-top: 200px; +} + +.footer-container a { + font-weight: 700; +} + +footer { + display: none; +} + +.media-link { + padding-right: 12px; + width: 48px; +} + +.img-code { + border-radius: 6px; + box-shadow: 1px 1px 12px 0 #333; +} + +.landing-code { + margin-top: 250px; + text-align: center; +} + +.mb-4 { + margin-bottom: 32px; +} diff --git a/docs/src/pages/index.module.css b/docs/src/pages/index.module.css new file mode 100644 index 000000000..0c9fbe609 --- /dev/null +++ b/docs/src/pages/index.module.css @@ -0,0 +1,61 @@ +/** + * CSS files with the .module.css suffix will be treated as CSS modules + * and scoped locally. + */ + +.heroBanner { + padding: 4rem 0; + text-align: center; + position: relative; + overflow: hidden; +} + +.heroText { + font-weight: 800; + max-width: 610px; + line-height: 1.1; + text-align: left; + font-size: 48px; +} + +.heroLeft { + margin-top: 250px; +} + +@media screen and (max-width: 996px) { + .heroBanner { + padding: 2rem; + } + + .heroLeft { + margin-top: 320px; + text-align: center; + } + + .heroText { + text-align: center; + font-size: 36px; + margin: 15px auto; + } +} + +.heroText svg { + display: inline-block !important; +} + +.heroText svg:first-child { + display: inline-block !important; + margin-bottom: -17px !important; + transform: rotateZ(359deg); +} + +.buttons { + display: flex; + align-items: center; + justify-content: center; +} + +.bg { + width: 100%; + height: 100vh; +} diff --git a/docs/src/pages/index.tsx b/docs/src/pages/index.tsx new file mode 100644 index 000000000..b756cd3e7 --- /dev/null +++ b/docs/src/pages/index.tsx @@ -0,0 +1,32 @@ +import useDocusaurusContext from "@docusaurus/useDocusaurusContext"; +import Layout from "@theme/Layout"; +import HomepageFeatures from "@site/src/components/HomepageFeatures"; + +import Footer from "@site/src/components/Footer"; +import Banner from "@site/src/components/Banner"; +import CodeExample from "@site/src/components/CodeExample"; + +function HomepageHeader() { + return ( + <> + + + +